※ 本質問文は用語の使用法が正確ではありません。
話の流れが分かり辛くならないようにあえて質問時のままとしております。
正確な用法に関しては yohhoy さんのご回答を参照してください。
前提・実現したいこと
C++17、及び C++20(予定)の規格に関する質問です。
lifetime が終了し、かつ storage が他のオブジェクトによって再利用されたオブジェクトを指しているポインタに対して、規格上どのような操作が許されるのか気になり、調べていました。
しかし規格のドラフトから適当な記述を見つける事ができず、困っています。
もしご存じの方がいらっしゃいましたらご助言をいただけないでしょうか。
C++17 (N4659)、及び C++20 (N4849) のドラフトを参照しています。
発生している問題
https://timsong-cpp.github.io/cppwp/n4659/basic.life#6
おそらく上記のあたりが該当の記述だと思ったのですが、上記の段落では以下のように述べられておりました。
Before the lifetime of an object has started but after the storage which the object will occupy has been allocated or, after the lifetime of an object has ended and before the storage which the object occupied is reused or released,
すなわち、「lifetime の終了後、その storage が解放または再利用されていないオブジェクト」を指すポインタに関する記述となっています。
「lifetime が終了し、かつ storage が再利用されているオブジェクト」を指すポインタについての記述は見つかりませんでした。
しかし上記の段落に付随する Example は、「lifetime が終了し、かつ storage が再利用されているオブジェクト」を指すポインタに関する例となっているように読めました。
以下は N4659 からの引用です
C++
1#include <cstdlib> 2 3struct B { 4 virtual void f(); 5 void mutate(); 6 virtual ~B(); 7}; 8 9struct D1 : B { void f(); }; 10struct D2 : B { void f(); }; 11 12void B::mutate() { 13 new (this) D2; // reuses storage — ends the lifetime of *this 14 f(); // undefined behavior 15 ... = this; // OK, this points to valid memory 16} 17 18void g() { 19 void* p = std::malloc(sizeof(D1) + sizeof(D2)); 20 B* pb = new (p) D1; 21 pb->mutate(); 22 *pb; // OK: pb points to valid memory 23 void* q = pb; // OK: pb points to valid memory 24 pb->f(); // undefined behavior, lifetime of *pb has ended 25}
g() における pb や、mutate() における this は「lifetime が終了し、かつ storage が再利用されているオブジェクト」を指すポインタになっているように思われます。
この Example がこの段落に存在することで混乱してしまいました。
私が読み間違えているだけでこの段落の記述は「lifetime が終了し、かつ storage が再利用されているオブジェクト」を指すポインタにも適用されるのでしょうか。
ソースコードの例
例えば、以下のような操作がそれぞれ Undefined Behavior となるのか、ならないのかが気になっています。
C++
1#include <cstdint> 2#include <new> 3 4int main() 5{ 6 std::uint32_t* p32 = new std::uint32_t[4]{}; 7 std::uint16_t* p16 = new (p32) std::uint16_t[4]{}; 8 *p32; // (a) 9 std::uint32_t lval = *p32 + 100; // (b) 10 std::uint32_t* p32_2 = p32 + 2; // (c) 11 *p32_2 = 0; // (d) 12 p32 = new (p32) std::uint32_t[4]; // (e) 13 delete [] p32; // (f) 14}
追記:
https://lists.isocpp.org/std-discussion/2020/04/0530.php
こちらのメールで非常に丁寧にご回答いただきました。簡単に要約させていただきます。
[basic.life]/6 は段落を通して以下のポインタについて語られています。
"any pointer that represents the address of the storage location where the object will be or was located"
([basic.life]/6 中の such a pointer は上記を指します)
私の誤解の原因は、
"Before the lifetime of an object has started but after the storage which the object will occupy has been allocated41 or, after the lifetime of an object has ended and before the storage which the object occupied is reused or released"
という条件が、[basic.life]/6 中で言及されるポインタ全体を修飾するものだと考えていたことでした。
実際には、上記の条件は一文目と二文目のみに関係するものとのことです。
(三文目は上記条件に当てはまらないものについての言及となります)
私の誤解にお付き合いいただきありがとうございました。
ベストアンサーについて、私の読み間違いを指摘してくださった yohhoy さんと非常に迷いましたが、問題解決のメールを出すきっかけとなった alphya さんとさせていただきました。
回答5件
あなたの回答
tips
プレビュー