質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.48%

  • C++

    3626questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

C++:配列型(サイズ含む)へのポインタをnewで生成したい

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 1,191

Chironian

C++総合1位

C/C++の配列へのポインタは要素へのポインタにて代用される場合が多いです。(int foo[3];とした時、fooint型へのポインタとなる等。)

しかし、C++の場合、配列の要素数まで含めた型を定義できます。
例えば、typedef int Int3Array[3];とすれば、Int3Arrayint[3]型として定義できます。
この時Int3Array*int[3]型へのポインタとなります。

そして、Int3Array* bar=new Int3Array;としたいのですが、できません。
MinGWの場合、error: cannot convert 'int*' to 'int (*)[3]' in initializationというエラーになります。
new[]が呼ばれてしまい、戻り値の型がint型へのポインタになってしまうのだと思います。

new[]ではなくnewを呼ばせる構文はないでしょうか?


【追記】
現在、開発中のライブラリにて配列型のnewをサポートするかどうか検討中です。
そもそもC++にて配列型をnewできないのであればエラー処理する予定です。
しかし、もし、配列型をnewできるのであればサポートしたいと考えています。


【実装しました】
raccyさんご提案のreinterpret_cast<>を使う方法でうまくいきました。私が何か見落として無ければ必要な機能に全て対応できた筈です。また、私に可能な確認とcatsforepawさんのclangでの確認により、使っても大きな問題にはならないだろうと判断しました。

最初にご提案頂いたraccyさんの回答をベスト・アンサーとさせて頂きました。
raccyさん、catsforepawさん、ありがとうございます。
また、epistemeさんもお付き合い、ありがとうございます。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+1

無理矢理キャストしたらなんかできました。でも、これで正しいのかどうかよくわかってません。

#include <iostream>
typedef int int3Array[3];

int main()
{
    int3Array *a = reinterpret_cast<int3Array *>(new int3Array());
    (*a)[0] = 1;
    (*a)[1] = 2;
    (*a)[2] = 3;
    std::cout << a << ": " << *a << ": {" << (*a)[0] << ", " << (*a)[1]
          << ", " << (*a)[2] << "}" << std::endl;
    return 0;
}


aと*aが同じなんですけど、それぞれへはちゃんとアクセスできるみたいです。配列へのポインタってそういう動きなんでしょうか、うーんわからない。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/07 16:44

    回答、ありがとうございます。

    あ、なるほど。

    msvcでステップ実行してみたところ、new[]で確保されてました。(その中で単にnewを呼んでました。)
    そして、delete[] a;で開放しないと警告が出ました。
    また、_CrtSetDbgFlag()を使ってメモリリーク検出されませんでした。
    ならば問題なさそうな気がします。

    MinGWではdelete a;もdelete[] a;も警告でませんでした。
    しかし、そもそも、int *b=new int[10];については、delete b; delete[] b;の両方がMinGW、msvcの両方で警告でないし...

    どうやらreinterpret_cast<>で実使用上は問題なさそうな気がします。

    ただ、処理系依存してそうな感じも少ししますので、もう少しだけオープンさせて下さい。

    キャンセル

  • 2016/05/07 17:09

    > aと*aが同じなんですけど、

    は、たぶん、aは配列型のインスタンスへのポインタで、*aは配列の先頭要素へのポインタではないかと思います。

    キャンセル

+1

C++11 なら 固定長配列には std::array がオススメ。

#include <array>
typedef std::array<int,3> Int3Array;
int3Array* bar = new Int3Array();

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/07 13:10

    回答、ありがとうございます。

    なるほど。しかし、それでは配列型とは異なります。
    といいますか、型を定義するのは私ではなく、開発中の自作ライブラリを使うユーザ側なので、可能なものなら配列型をサポートしたいと考えています。
    そして、逆に配列型のnewができないのであればエラーとする予定です。

    説明不足で申し訳ないです。

    キャンセル

  • 2016/05/07 14:13

    std::array<T,N> は T[N] を内包しててその先頭ポインタを取り出せますけど、それでもダメ?

    int3Array* bar = new Int3Array();
    int* head = bar->data();

    キャンセル

  • 2016/05/07 14:40

    std::array<>を含む標準ライブラリのコンテナは全てサポートする予定です。
    そして、std::array<>は要素数Nを明示的に与える必要があるため、通常の配列の方が便利な場面(初期化リストで要素数Nを与えたいケース)もあります。
    なので、可能であれば配列型もサポートしたいのです。

    キャンセル

+1

いろいろ試してみましたが、raccyさんが回答されているようにキャストするとそれっぽく動きはしますが、deleteが怪しいです。

このコードをVC++/g++/clangでテストしてみました。

#include <iostream>

static int count = 0;

struct Hoge
{
    int No;

    Hoge()
    {
        this->No = count++;
        std::cout << "create " << this->No << std::endl;
    }

    ~Hoge()
    {
        std::cout << "delete " << this->No << std::endl;
    }
};

int main()
{
    typedef Hoge HogeArray[5];

    HogeArray *p = reinterpret_cast<HogeArray *>(new HogeArray);
    std::cout << "p=" << p << std::endl;
    std::cout << "*p=" << *p << std::endl;
    for(auto&& x : *p)
        std::cout << "No=" << x.No << std::endl;
    delete p;
    //delete[] p;
    return 0;
}


出力内容(VC++) ※g++,clangでもアドレスの形式が違うだけでほぼ同様

create 0
create 1
create 2
create 3
create 4
p=00000297E7153BE8
*p=00000297E7153BE8
No=0
No=1
No=2
No=3
No=4
delete 4
delete 3
delete 2
delete 1
delete 0


いずれもコンパイルでき、delete pでもちゃんと配列の要素に対してデストラクタが呼ばれています。ただし、VC++とclangではdelete pではdeleteが配列形式でないという警告が出てdelete[] pだと警告は出ませんでした。
VC++,g++,clangともにdelete[] pでも問題なく動きます。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/07 17:04

    色々試して頂いて、ありがとうございます。
    特にclangでのトライありがたいです。

    > clangではdelete p,delete[] pともにエラーが発生してコンパイルできませんでした。

    なるほど。
    どんなエラーメッセージでした? 規格違反っぽいメッセージじゃなかったですか?

    キャンセル

  • 2016/05/07 17:17

    すみません。エラーの内容をよく見ずに書いてしまったのですが、clangでもコンパイルは通りました。clang++の++を付け忘れてコンパイルしたのでエラーになっていただけです。
    (回答の方を書き直します。)

    結果としては、clangはVC++と同じく`delete p`では配列に対するdeleteが`delete[]`になっていないというものです。

    キャンセル

  • 2016/05/07 17:25

    了解です。
    clangでも通るなら使ってよさそうですね。

    キャンセル

関連した質問

同じタグがついた質問を見る

  • C++

    3626questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。