web-dev-qa-db-ja.com

演算子newはメモリをゼロに初期化します

そのようなコードがあります:

#include <iostream>

int main(){
  unsigned int* wsk2 = new unsigned int(5);
  std::cout << "wsk2: " << wsk2 << " " << *wsk2 << std::endl;
  delete wsk2;
  wsk2 = new unsigned int;
  std::cout << "wsk2: " << wsk2 << " " << *wsk2 << std::endl;
  return 0;
}

結果:

wsk2: 0x928e008 5
wsk2: 0x928e008 0

newはメモリをゼロで初期化しないことを読みました。しかし、ここではそうであるようです。どのように機能しますか?

65
scdmb

2つのバージョンがあります。

_wsk = new unsigned int;      // default initialized (ie nothing happens)
wsk = new unsigned int();    // zero    initialized (ie set to 0)
_

配列にも機能します:

_wsa = new unsigned int[5];   // default initialized (ie nothing happens)
wsa = new unsigned int[5](); // zero    initialized (ie all elements set to 0)
_

以下のコメントへの回答。

ええと... new unsigned int[5]()は整数をゼロにすることを確認しますか?

明らかにはい:

[C++ 11:5.3.4/15]:タイプTのオブジェクトを作成するnew-expressionは、次のようにそのオブジェクトを初期化します。new-initializerが省略されると、オブジェクトはデフォルトで初期化されます(8.5)。初期化が実行されない場合、オブジェクトの値は不確定です。それ以外の場合、new-initializerは、直接初期化の8.5の初期化規則に従って解釈されます。

_#include <new>
#include <iostream>


int main()
{
    unsigned int   wsa[5] = {1,2,3,4,5};

    // Use placement new (to use a know piece of memory).
    // In the way described above.
    // 
    unsigned int*    wsp = new (wsa) unsigned int[5]();

    std::cout << wsa[0] << "\n";   // If these are zero then it worked as described.
    std::cout << wsa[1] << "\n";   // If they contain the numbers 1 - 5 then it failed.
    std::cout << wsa[2] << "\n";
    std::cout << wsa[3] << "\n";
    std::cout << wsa[4] << "\n";
}
_

結果:

_> g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
Target: x86_64-Apple-darwin13.2.0
Thread model: posix
> g++ t.cpp
> ./a.out
0
0
0
0
0
>
_
161
Martin York

operator newは、メモリを何にでも初期化することは保証されていません。また、new-expressionは、unsigned intなしnew-initializerは、オブジェクトに不定値を残します。

初期化されていないオブジェクトの値を読み取ると、未定義の動作になります。 未定義の動作は、悪影響なしで値0に評価することを含みますが、何かが発生する可能性があるため、それを引き起こさないようにしてください。

C++ 11で使用される言語は、割り当てられたオブジェクトがdefault-initializedであることです。これは、非クラス型の場合、初期化が実行されないことを意味します。これは、C++ 03のdefault-initializedの意味とは異なります。

19
CB Bailey

一部のコンパイラーでは、newのデバッグバージョンがデータを初期化しますが、信頼できるものは何もありません。

前回の使用でメモリが0になった可能性もあります。 deleteとnewの間でメモリに何も起こらないと仮定しないでください。あなたが気づいたことのない何かがバックグラウンドで行われる可能性があります。また、同じポインタ値は同じ物理メモリではない場合があります。メモリページは移動され、ページアウトおよびページインされます。ポインタは、以前とはまったく異なる場所にマッピングされる場合があります。

結論:メモリの場所を特に初期化していない場合、その内容については何も想定できません。メモリマネージャは、メモリを使用するまで特定の物理メモリの場所を割り当てない場合があります。

最新のメモリ管理は驚くほど複雑ですが、C++プログラマとしてはあまり気にしません(ほとんど‡)。ルールに従ってプレイすれば、トラブルに巻き込まれることはありません。

‡ページ違反を減らすために最適化するかどうか気にするかもしれません。

4
Michael J

これはoperator newではなく、new演算子です。実際には大きな違いがあります!違いは、operator newは生メモリを返す関数です。 new演算子を使用すると、コンストラクターが呼び出されます。 operator newではなく、そのintの値を設定しているのはコンストラクターです。