web-dev-qa-db-ja.com

newで割り当てられたメモリを再割り当てしても安全ですか?

記述内容 herenewfree storeに割り当て、mallocheapと2つの用語はしばしば同じことを意味します。

記述内容 here から、reallocはメモリブロックを新しい場所に移動する場合があります。無料のストアとヒープが2つの異なるメモリ空間である場合、それは何か問題を意味しますか?

具体的には安全に使用できるかどうか知りたい

int* data = new int[3];
// ...
int* mydata = (int*)realloc(data,6*sizeof(int));

そうでない場合、reallocで安全にnewメモリを割り当てる他の方法はありますか?新しい領域とmemcpyの内容を割り当てることができましたが、私が理解しているところによると、reallocは可能であれば同じ領域を使用する場合があります。

33
Jan Turoň

C++がreallocに追加する可能性のある唯一の制限は、C++のmalloc/calloc/realloc::operator newに関して実装してはならないことです。そしてそのfree::operator deleteの観点から実装してはなりません(C++ 14 [c.malloc] p3-4による)。

これは、探している保証がC++に存在しないことを意味します。ただし、これは、mallocに関して::operator newを実装できることも意味します。そして、それを行うと、理論的には、::operator newの結果をreallocに渡すことができます。

実際には、newの結果が::operator newの結果と一致しない可能性について心配する必要があります。 C++コンパイラは、複数のnew式を組み合わせて、1つの::operator new呼び出しを使用します。これは、標準で許可されていないときにコンパイラーがすでに行っていたものであり、IIRCであり、標準では許可されています(C++ 14 [expr.new] p10ごと)。つまり、この経路をたどったとしても、newポインタをreallocに渡すことが、未定義の動作ではなくなったとしても、意味のあることを実行できるという保証はありません。

16
user743382

一般に、それを行わないでください。 非自明な初期化でユーザー定義型を使用している場合、再割り当てコピー解放の場合、オブジェクトのデストラクタが勝ちますreallocによって呼び出されない。コピーするとき、コピーconstructorも呼び出されません。これは、object lifetimeを参照)の誤った使用により、未定義の動作を引き起こす可能性があります。 [basic.life])。

1オブジェクトの存続期間は、オブジェクトの実行時プロパティです。オブジェクトがクラスまたは集約型であり、そのメンバーの1つが自明なデフォルトコンストラクター以外のコンストラクターによって初期化されている場合、そのオブジェクトは自明ではない初期化を持つと言われます。 [注:簡単なコピー/移動コンストラクタによる初期化は、重要な初期化ではありません。 —エンドノート]

タイプTのオブジェクトの存続期間は、次の場合に始まります。

—タイプTの適切な配置とサイズのストレージが取得されます。

—オブジェクトに重要な初期化がある場合、その初期化は完了しています。

タイプTのオブジェクトの存続期間は、次の場合に終了します。

— Tが重要なデストラクタ(12.4)を持つクラス型の場合、デストラクタ呼び出しが開始されます。

—オブジェクトが占有するストレージは再利用または解放されます。

そして後で(私の強調):

3この国際規格全体でオブジェクトに帰属するプロパティは、特定のオブジェクトに適用されますその存続期間中のみ

そのため、オブジェクトのライフタイムのoutを使用したくないのです。

8
Paolo M

安全ではなく、エレガントでもありません。

再割り当てをサポートするためにnew/deleteをオーバーライドすることは可能ですが、その場合はコンテナーの使用を検討することもできます。

はい-newが最初に実際にmallocを呼び出した場合(たとえば、これはVC++ newが機能する方法です)。

それ以外はありません。 (newmallocと呼ばれるため)メモリの再割り当てを決定すると、コードはコンパイラ固有であり、コンパイラ間で移植できなくなります。

(私はこの答えが多くの開発者を混乱させるかもしれないことを知っていますが、私は答えは慣用性だけでなく実際の事実に依存します)。

4
David Haim

それは安全ではありません。まず、reallocに渡すポインターは、mallocまたはreallocから取得したものである必要があります。 http://en.cppreference.com/w/cpp/memory/c/realloc

第2に、new int [3]の結果は、割り当て関数の結果と同じである必要はありません-要素の数を格納するために追加のスペースを割り当てることができます。

(そしてintよりも複雑な型の場合、reallocはコピーまたは移動コンストラクターを呼び出さないため、安全ではありません。)

4
Alan Stokes

一般的には違います。

安全にするために守らなければならないことがたくさんあります。

  1. タイプをビット単位でコピーしてソースを破棄することは安全でなければなりません。
  2. デストラクタは簡単であるか、割り当てを解除する要素をインプレース破棄する必要があります。
  3. コンストラクタは簡単ですが、新しい要素をインプレースで構築する必要があります。

自明な型は上記の要件を満たします。

加えて:

  1. new[]- functionは、変更を加えずにmallocにリクエストを渡す必要があります。また、サイドでの簿記も行いません。これを強制するには、グローバルnew []とdelete []、またはそれぞれのクラスのものを置き換えます。
  2. コンパイラーは、割り当てられた要素の数などを保存するために、より多くのメモリを要求してはなりません。
    それを強制する方法はありませんが、型がQuality of Implementationの問題として簡単なデストラクタを持っている場合、コンパイラはそのような情報を保存するべきではありません。
4
Deduplicator

(すべての場合ではありませんが)できるかもしれませんが、できないはずです。データテーブルのサイズを変更する必要がある場合は、std::vector代わりに。

使用方法の詳細は、他の SO質問 に記載されています。

3
nikaltipar