ページ 11

要素数0の配列

Posted: 2011年3月28日(月) 16:31
by dom
要素数0の配列を

   int array[0];

のように宣言すると,もちろんコンパイルエラーになります.
しかし,

   int *p = new int [0];
   p[0] = 10;
   cout << p[0] << endl;

などとすると実行できてしまいます.これはどういう仕組みなのでしょうか.
また,この使用法は問題ないのでしょうか.

Re: 要素数0の配列

Posted: 2011年3月28日(月) 17:00
by しひ
int arrはint *(arr+i)の糖衣構文です。

コード:

#include <iostream>

int main()
{
	int *p = new int [0];
	p[0] = 10;
	std::cout << p[0] << std::endl;
	
	int *q = new int;
	q[0] = 20;
	std::cout << q[0] << std::endl;

	int *r = new int( 30 );
	std::cout << r[0] << std::endl;

	delete p;
	delete q;
	delete r;
}
わざわざその書き方をしたい理由はさっぱりわかりませんが、
せめてdeleteするなりスマートポインタを使うなりして下さい。

Re: 要素数0の配列

Posted: 2011年3月28日(月) 17:25
by maru
dom さんが書きました:

コード:

   int *p = new int [0];
   p[0] = 10;
   cout << p[0] << endl;
などとすると実行できてしまいます.これはどういう仕組みなのでしょうか.
最初の文は要素数0の int 領域を確保して、そのアドレスを返します。
つまりメモリアドレスは返ってくるが、その領域は使えない(使ってはいけない)
2、3番目の文は、その使ってはいけない領域にデータを書込み、読み出しています。
動作したのは、たまたまです。運よくそのアドレスのデータは他に使用されていなかった為でしょう。
dom さんが書きました:また,この使用法は問題ないのでしょうか.
もちろん大問題です。こんな使い方を決して行ってはいけません。

Re: 要素数0の配列

Posted: 2011年3月28日(月) 17:27
by めるぽん
> これはどういう仕組みなのでしょうか.
簡単に言えば、仕様です。
C言語からある通常の配列は、要素数 0 個の配列を許可していません。
しかし、C++ の new を使った配列の動的確保での要素数は 0 個を許可しています。

> また,この使用法は問題ないのでしょうか.
問題があります。
p[0] にアクセスする必要があるなら少なくとも 1 個の要素が必要です。
要素数が 0 ということは、一切の要素が存在していないということなので、要素へのアクセスは決してできません。

コード:

int *p = new int [1];
と、1以上を指定するべきです。

また、new int[] で確保した配列は、delete[] によって解放する必要があります。
実際は、int 等の組み込み型であれば単に delete しても問題無く動作すると思いますが、仕様的には未定義動作です。

コード:

int* p = new int[10];
// delete p; // 未定義動作
delete[] p; // OK

Re: 要素数0の配列

Posted: 2011年3月28日(月) 17:59
by dom
ありがとうございます.やはりこのような使い方はダメなんですね.

質問の理由ですが,
コンストラクタで引数に応じた要素数の配列を生成し,デストラクタでそれを開放する
ようなことをしていたのですが,要素数が0でも問題なさそうに動作したので気になって質問してみました.

Re: 要素数0の配列

Posted: 2011年3月28日(月) 18:21
by めるぽん
> やはりこのような使い方はダメなんですね.
このような、がどういった使い方によりますね。

例えば、以下のように 0 個の要素を確保するのは問題ありません

コード:

class Array {
    int* p;
    int size;

public:
    Array(int size) : p(new int[size]), size(size) { }
    ~Array() { delete[] p; }
    int length() const { return size; }
    int& operator[](int n) const { return p[n]; }
    // その他は省略
};

int main() {
    Array ar(0);
    for (int i = 0; i < ar.length(); i++) {
        ar[i] = 10; // ここは決して実行されない
    }
}
つまり、0 個の要素を new しても、p[0] や *p といった操作で実際に要素にアクセスしなければ問題ないのです。
この例では ar.length() が 0 で、for 文の中身が実行されないため、正しく動作します。

Re: 要素数0の配列

Posted: 2011年3月28日(月) 21:56
by しひ
new[]演算子のことを忘れてて訳分かんないこと書いてました。申し訳ない。