回答編集履歴
8
回答の編集
answer
CHANGED
@@ -66,7 +66,7 @@
|
|
66
66
|
|
67
67
|
(c): p32 は有効なポインタであるため、これは問題ありません
|
68
68
|
|
69
|
-
(d): [basic.life]/7.1 より、「オブジェクトにアクセスするために glvalue が使用される」ため、UB
|
69
|
+
(d): ~~ [basic.life]/7.1 より、「オブジェクトにアクセスするために glvalue が使用される」ため、UB ~~ lifetime が終了したオブジェクトへのアクセスではないため、UB ではありません(コメント欄参照)
|
70
70
|
|
71
71
|
(e): この時点で、タイプ std::uint16_t の 4 つのオブジェクトは、ストレージの再利用のために lifetime が終了しています。ただし、std::uint32_t タイプの 4 つのオブジェクトは、 `{}` がないために作成されていません
|
72
72
|
|
7
回答の編集
answer
CHANGED
@@ -45,7 +45,7 @@
|
|
45
45
|
|
46
46
|
"Indirection" からの文が適用されないという解釈の根拠は cppreference の記事でしたが、このサイトも C++ の公式のものだというわけではないので、上記のような規格の記述に一貫性のある解釈の方が妥当だと思います。
|
47
47
|
|
48
|
-
また、このような解釈では、例示された (c), (d), (e), (f) の操作は、未定義動作となる条件である [basic.life]/6.1 から 6.5 に該当しないためどれも適格な操作だと考えられます。ただし、(a), (b) は strict aliasing rule によって未定義動作だと考えられます。
|
48
|
+
また、このような解釈では、例示された (c), (d), (e), (f) の操作は、未定義動作となる条件である [basic.life]/6.1 から 6.5 に該当しないためどれも適格な操作だと考えられます。ただし、(a), (b) は strict aliasing rule によって未定義動作だと考えられます。
|
49
49
|
|
50
50
|
---
|
51
51
|
[追記 2]
|
6
追記
answer
CHANGED
@@ -45,4 +45,29 @@
|
|
45
45
|
|
46
46
|
"Indirection" からの文が適用されないという解釈の根拠は cppreference の記事でしたが、このサイトも C++ の公式のものだというわけではないので、上記のような規格の記述に一貫性のある解釈の方が妥当だと思います。
|
47
47
|
|
48
|
-
また、このような解釈では、例示された (c), (d), (e), (f) の操作は、未定義動作となる条件である [basic.life]/6.1 から 6.5 に該当しないためどれも適格な操作だと考えられます。ただし、(a), (b) は strict aliasing rule によって未定義動作だと考えられます。
|
48
|
+
また、このような解釈では、例示された (c), (d), (e), (f) の操作は、未定義動作となる条件である [basic.life]/6.1 から 6.5 に該当しないためどれも適格な操作だと考えられます。ただし、(a), (b) は strict aliasing rule によって未定義動作だと考えられます。(@onihusube9 on Twitter さんにご指摘をいただきました。ありがとうございます。)
|
49
|
+
|
50
|
+
---
|
51
|
+
[追記 2]
|
52
|
+
|
53
|
+
ISO C++ Standard - Discussion へこの質問を送り、回答をいただきました:
|
54
|
+
https://lists.isocpp.org/std-discussion/2020/04/0511.php
|
55
|
+
|
56
|
+
この回答によれば、[basic.life]/6 の記述は「あるオブジェクトの生存期間(lifetime)が終了したあとに、同オブジェクトが占めていたストレージ上にオブジェクトが生成されている、その同ストレージへのポインタ」にも適用されるようです。
|
57
|
+
|
58
|
+
また、例示された操作については次のようになるようです。
|
59
|
+
|
60
|
+
(a): UB ではありません。なぜなら:
|
61
|
+
[basic.lval]/1.4 "lvalue は、xvalue でない glvalue です"
|
62
|
+
[basic.life]/6 "そのようなポインターを介した間接指定は許可されますが、結果の lvalue は、以下で説明するように、限られた方法でのみ使用できます"
|
63
|
+
[basic.life]/7 "その値に依存しない glvalue のプロパティの使用は well-defined です"
|
64
|
+
|
65
|
+
(b): 式 *p32 + 100 は、「その値に依存する glvalue のプロパティを使用している」ため UB
|
66
|
+
|
67
|
+
(c): p32 は有効なポインタであるため、これは問題ありません
|
68
|
+
|
69
|
+
(d): [basic.life]/7.1 より、「オブジェクトにアクセスするために glvalue が使用される」ため、UB
|
70
|
+
|
71
|
+
(e): この時点で、タイプ std::uint16_t の 4 つのオブジェクトは、ストレージの再利用のために lifetime が終了しています。ただし、std::uint32_t タイプの 4 つのオブジェクトは、 `{}` がないために作成されていません
|
72
|
+
|
73
|
+
(f): これにより、ストレージの割り当てが解除されます。std::uint32_t は no non-trivial destructor をもつため UB ではありません
|
5
書式の改善
answer
CHANGED
@@ -41,7 +41,7 @@
|
|
41
41
|
---
|
42
42
|
[追記]
|
43
43
|
|
44
|
-
nus_miz さんのご指摘のように、[basic.life]/6 の記述は一見すると「あるオブジェクト
|
44
|
+
nus_miz さんのご指摘のように、[basic.life]/6 の記述は一見すると「あるオブジェクトの生存期間(lifetime)が終了したあとに、同オブジェクトが占めていたストレージ上にオブジェクトが生成されていない、その同ストレージへのポインタ」に関する記述だと読めるが、"Indirection through such a..." からの文を含めた "Otherwise" 節以降の文は「あるオブジェクトの生存期間(lifetime)が終了したあとに、同オブジェクトが占めていたストレージ上にオブジェクトが生成されている、その同ストレージへのポインタ」にも適用される、という解釈だと、付随する Example がこの位置にあることや、`*pb` の間接参照が適格だということに説明が付きそうです。
|
45
45
|
|
46
46
|
"Indirection" からの文が適用されないという解釈の根拠は cppreference の記事でしたが、このサイトも C++ の公式のものだというわけではないので、上記のような規格の記述に一貫性のある解釈の方が妥当だと思います。
|
47
47
|
|
4
用語の修正
answer
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
[4/10 17:18 yohhoy さんの回答より、用語の使い方を修正しました]
|
2
|
+
|
1
3
|
> lifetime が終了し、かつ storage が他のオブジェクトによって再利用されたオブジェクトを指しているポインタに対して、規格上どのような操作が許されるのか
|
2
4
|
|
3
5
|
基本的には、[basic.life]/8 に対応する記述があるようです。[生存期間 - cppreference.com](https://ja.cppreference.com/w/cpp/language/lifetime) による日本語の説明は次の通りです:
|
@@ -21,15 +23,15 @@
|
|
21
23
|
|
22
24
|
> ... Otherwise, such a pointer refers to allocated storage ([basic.stc.dynamic.deallocation]), and using the pointer as if the pointer were of type void*, is well-defined.
|
23
25
|
|
24
|
-
が「lifetime
|
26
|
+
が「あるオブジェクトの生存期間(lifetime)が終了したあとに、同オブジェクトが占めていたストレージ上にオブジェクトが生成されている、その同ストレージへのポインタ」にも適用されるように読み取れます。
|
25
27
|
|
26
28
|
ただし、"Otherwise" 節の次の "Indirection through such a..." からの文は、[生存期間 - cppreference.com](https://ja.cppreference.com/w/cpp/language/lifetime) の対応する箇所に「オブジェクトの生存期間が開始する前かつオブジェクトが占める記憶域が確保された後、またはオブジェクトの生存期間が終了した後かつオブジェクトが占めていた記憶域が再利用または解放される前」と指定があるので適用されないように思えます。また、上記 cppreference の記事では "Otherwise" 節や [basic.life]/6 に付随する Example については言及されていませんでした。
|
27
29
|
|
28
|
-
(個人的には [basic.life]/6 は「
|
30
|
+
(個人的には [basic.life]/6 は「あるオブジェクトの生存期間(lifetime)が終了したあとに、同オブジェクト#1が占めていたストレージ上にオブジェクトが生成されていない、その同ストレージへのポインタ」に関する記述となるようにも読めると思います...)
|
29
31
|
|
30
32
|
> 例えば、以下のような操作がそれぞれ Undefined Behavior となるのか、ならないのか
|
31
33
|
|
32
|
-
ここでは、上記の StackOverflow の回答の解釈([basic.life]/6 の "Otherwise" 節の記述が「lifetime
|
34
|
+
ここでは、上記の StackOverflow の回答の解釈([basic.life]/6 の "Otherwise" 節の記述が「あるオブジェクトの生存期間(lifetime)が終了したあとに、同オブジェクトが占めていたストレージ上にオブジェクトが生成されている、その同ストレージへのポインタ」にも適用される)に従って回答します。
|
33
35
|
|
34
36
|
(a), (b): この場合、`p32`の型が`void*`型であるかのようにポインターを使用することができますが、`void*`型変数の間接参照はできないため Undefined Behavior
|
35
37
|
(c): `p32`の型を`void*`と仮定したとき、キャストなしに代入することはできないので Undefined Behavior
|
@@ -39,7 +41,7 @@
|
|
39
41
|
---
|
40
42
|
[追記]
|
41
43
|
|
42
|
-
nus_miz さんのご指摘のように、[basic.life]/6 の記述は一見すると「
|
44
|
+
nus_miz さんのご指摘のように、[basic.life]/6 の記述は一見すると「あるオブジェクト#1の生存期間(lifetime)が終了したあとに、同オブジェクト#1が占めていたストレージ上にオブジェクト#2が生成されていない、その同ストレージへのポインタ」に関する記述だと読めるが、"Indirection through such a..." からの文を含めた "Otherwise" 節以降の文は「あるオブジェクトの生存期間(lifetime)が終了したあとに、同オブジェクトが占めていたストレージ上にオブジェクトが生成されている、その同ストレージへのポインタ」にも適用される、という解釈だと、付随する Example がこの位置にあることや、`*pb` の間接参照が適格だということに説明が付きそうです。
|
43
45
|
|
44
46
|
"Indirection" からの文が適用されないという解釈の根拠は cppreference の記事でしたが、このサイトも C++ の公式のものだというわけではないので、上記のような規格の記述に一貫性のある解釈の方が妥当だと思います。
|
45
47
|
|
3
文面の修正
answer
CHANGED
@@ -43,4 +43,4 @@
|
|
43
43
|
|
44
44
|
"Indirection" からの文が適用されないという解釈の根拠は cppreference の記事でしたが、このサイトも C++ の公式のものだというわけではないので、上記のような規格の記述に一貫性のある解釈の方が妥当だと思います。
|
45
45
|
|
46
|
-
また、このような解釈では、例示された (c), (d), (e), (f) の操作は、未定義動作となる条件である [basic.life]/6.1 から 6.5 に該当しないためどれも適格な操作だと考えられます。ただし、(a), (b) は strict aliasing rule に
|
46
|
+
また、このような解釈では、例示された (c), (d), (e), (f) の操作は、未定義動作となる条件である [basic.life]/6.1 から 6.5 に該当しないためどれも適格な操作だと考えられます。ただし、(a), (b) は strict aliasing rule によって未定義動作だと考えられます。
|
2
追記の変更
answer
CHANGED
@@ -43,4 +43,4 @@
|
|
43
43
|
|
44
44
|
"Indirection" からの文が適用されないという解釈の根拠は cppreference の記事でしたが、このサイトも C++ の公式のものだというわけではないので、上記のような規格の記述に一貫性のある解釈の方が妥当だと思います。
|
45
45
|
|
46
|
-
また、このような解釈では、例示された (
|
46
|
+
また、このような解釈では、例示された (c), (d), (e), (f) の操作は、未定義動作となる条件である [basic.life]/6.1 から 6.5 に該当しないためどれも適格な操作だと考えられます。ただし、(a), (b) は strict aliasing rule に反するので未定義動作だと考えられます。
|
1
追記
answer
CHANGED
@@ -34,4 +34,13 @@
|
|
34
34
|
(a), (b): この場合、`p32`の型が`void*`型であるかのようにポインターを使用することができますが、`void*`型変数の間接参照はできないため Undefined Behavior
|
35
35
|
(c): `p32`の型を`void*`と仮定したとき、キャストなしに代入することはできないので Undefined Behavior
|
36
36
|
(d): (a), (b) と同じ理由により Undefined Behavior
|
37
|
-
(e), (f): [basic.life]/8 の条件を満たすので適格
|
37
|
+
(e), (f): [basic.life]/8 の条件を満たすので適格
|
38
|
+
|
39
|
+
---
|
40
|
+
[追記]
|
41
|
+
|
42
|
+
nus_miz さんのご指摘のように、[basic.life]/6 の記述は一見すると「lifetime の終了後、その storage が解放または再利用されていないオブジェクト」を指すポインタに関する記述だと読めるが、"Indirection through such a..." からの文を含めた "Otherwise" 節以降の文は「lifetime が終了し、かつ storage が再利用されているオブジェクト」を指すポインタにも適用される、という解釈だと、付随する Example がこの位置にあることや、`*pb` の間接参照が適格だということに説明が付きそうです。
|
43
|
+
|
44
|
+
"Indirection" からの文が適用されないという解釈の根拠は cppreference の記事でしたが、このサイトも C++ の公式のものだというわけではないので、上記のような規格の記述に一貫性のある解釈の方が妥当だと思います。
|
45
|
+
|
46
|
+
また、このような解釈では、例示された (a) から (f) の操作は、未定義動作となる条件である [basic.life]/6.1 から 6.5 に該当しないためどれも適格な操作だと考えられます。
|