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

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

新規登録して質問してみよう
ただいま回答率
86.12%
C++

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

解決済

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

Chironian
Chironian

総合スコア23251

C++

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

3回答

0グッド

2クリップ

2770閲覧

投稿2016/05/07 03:44

編集2016/05/08 08:59

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ページの「注目」タブのフィードに表示されやすくなります。

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

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

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

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

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

適切な質問に修正を依頼しましょう。

回答3

1

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

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

C++

1#include <iostream> 2 3static int count = 0; 4 5struct Hoge 6{ 7 int No; 8 9 Hoge() 10 { 11 this->No = count++; 12 std::cout << "create " << this->No << std::endl; 13 } 14 15 ~Hoge() 16 { 17 std::cout << "delete " << this->No << std::endl; 18 } 19}; 20 21int main() 22{ 23 typedef Hoge HogeArray[5]; 24 25 HogeArray *p = reinterpret_cast<HogeArray *>(new HogeArray); 26 std::cout << "p=" << p << std::endl; 27 std::cout << "*p=" << *p << std::endl; 28 for(auto&& x : *p) 29 std::cout << "No=" << x.No << std::endl; 30 delete p; 31 //delete[] p; 32 return 0; 33}

出力内容(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 07:57

編集2016/05/07 08:22
catsforepaw

総合スコア5936

Chironian👍を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

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

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

このような回答には修正を依頼しましょう。

回答へのコメント

Chironian

2016/05/07 08:04

色々試して頂いて、ありがとうございます。 特にclangでのトライありがたいです。 > clangではdelete p,delete[] pともにエラーが発生してコンパイルできませんでした。 なるほど。 どんなエラーメッセージでした? 規格違反っぽいメッセージじゃなかったですか?
catsforepaw

2016/05/07 08:17

すみません。エラーの内容をよく見ずに書いてしまったのですが、clangでもコンパイルは通りました。clang++の++を付け忘れてコンパイルしたのでエラーになっていただけです。 (回答の方を書き直します。) 結果としては、clangはVC++と同じく`delete p`では配列に対するdeleteが`delete[]`になっていないというものです。
Chironian

2016/05/07 08:25

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

1

ベストアンサー

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

C++

1#include <iostream> 2typedef int int3Array[3]; 3 4int main() 5{ 6 int3Array *a = reinterpret_cast<int3Array *>(new int3Array()); 7 (*a)[0] = 1; 8 (*a)[1] = 2; 9 (*a)[2] = 3; 10 std::cout << a << ": " << *a << ": {" << (*a)[0] << ", " << (*a)[1] 11 << ", " << (*a)[2] << "}" << std::endl; 12 return 0; 13}

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

投稿2016/05/07 06:07

raccy

総合スコア21689

Chironian👍を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

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

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

このような回答には修正を依頼しましょう。

回答へのコメント

Chironian

2016/05/07 07: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<>で実使用上は問題なさそうな気がします。 ただ、処理系依存してそうな感じも少ししますので、もう少しだけオープンさせて下さい。
Chironian

2016/05/07 08:09

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

1

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

C++

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

投稿2016/05/07 04:01

episteme

総合スコア15998

yohhoy👍を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

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

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

このような回答には修正を依頼しましょう。

回答へのコメント

Chironian

2016/05/07 04:10

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

2016/05/07 05:13

std::array<T,N> は T[N] を内包しててその先頭ポインタを取り出せますけど、それでもダメ? int3Array* bar = new Int3Array(); int* head = bar->data();
Chironian

2016/05/07 05:40

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

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

ただいまの回答率
86.12%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

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

C++

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