配列に対する移植可能な配置の新機能
標準ライブラリの配置 new 演算子を使用すると、指定したアドレスにメモリを割り当てることができます。ただし、配列で使用すると、返されたポインターと渡されたアドレスの間に矛盾が生じる可能性があるため、移植性に関する懸念が生じます。
問題の理解
配置 new を使用する場合配列の場合、返されるポインタは指定されたアドレスと一致しない可能性があります。これについては、C 標準の 5.3.4 の注 12 で説明されています。その結果、配列専用のバッファの割り当てが問題になります。
次の例を考えてみましょう。
#include <iostream> #include <new> class A { public: A() : data(0) {} ~A() {} int data; }; int main() { const int NUMELEMENTS = 20; char *pBuffer = new char[NUMELEMENTS * sizeof(A)]; A *pA = new(pBuffer) A[NUMELEMENTS]; // Output may show pA as four bytes higher than pBuffer std::cout << "Buffer address: " << pBuffer << ", Array address: " << pA << std::endl; delete[] pBuffer; return 0; }
この例は、Microsoft Visual Studio ではメモリ破損を引き起こすことがよくあります。メモリを調べると、コンパイラが配列割り当ての先頭に 4 バイトを付加し、おそらく配列要素の数を保存していることがわかります。この動作は、使用するコンパイラとクラスによって異なります。
移植可能なソリューション
この移植性の問題に対処するには、配置 new を配列に直接使用することは避けてください。代わりに、placement new:
#include <iostream> #include <new> class A { public: A() : data(0) {} ~A() {} int data; }; int main() { const int NUMELEMENTS = 20; char *pBuffer = new char[NUMELEMENTS * sizeof(A)]; A *pA = (A*)pBuffer; for (int i = 0; i < NUMELEMENTS; ++i) { pA[i] = new (pA + i) A(); } std::cout << "Buffer address: " << pBuffer << ", Array address: " << pA << std::endl; // Remember to manually destroy each element for (int i = 0; i < NUMELEMENTS; ++i) { pA[i].~A(); } delete[] pBuffer; return 0; }
を使用して配列の各要素を個別に割り当てることを検討してください。どのアプローチを採用しても、メモリ リークを防ぐには、バッファを削除する前に各配列要素を手動で破棄することが重要です。
以上がC 配列での新しい配置の使用は移植可能ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。