Skip to content

Commit 41a9acd

Browse files
committed
C++26: 「返却された左辺値から暗黙変換された一時オブジェクトが参照に束縛されることを禁止する」を追加 (close #1322)
1 parent 91bc83e commit 41a9acd

File tree

3 files changed

+61
-2
lines changed

3 files changed

+61
-2
lines changed

implementation-status.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@
301301
| P2558R2: [基本文字集合に@、$、\`を追加](/lang/cpp26/add_atsign_dollar_graveaccent_to_the_basic_character_set.md) | C言語との互換性のためにこれらの文字を基本文字集合に追加 | | Yes | | |
302302
| P2662R3: [パラメータパックへのインデックスアクセスを許可](/lang/cpp26/pack_indexing.md.nolink) | 可変引数テンプレートのパラメータパックに添字アクセスできるようにする | 15 | | | |
303303
| P2864R2: [非推奨となっていた列挙値から算術型への暗黙変換を削除](/lang/cpp26/remove_deprecated_arithmetic_conversion_on_enumerations.md) | C++20から非推奨となっていた列挙値への算術演算で算術型に暗黙変換される仕様を削除 | 14 | 18 | | |
304-
| P2748R5: [返却された左辺値から暗黙変換された一時オブジェクトが参照に束縛されることを禁止する](/lang/cpp26/disallow_binding_a_returned_glvalue_to_a_temporary.md.nolink) | 寿命切れの変数によって引き起こされるバグを防止する | 14 | 19 | | |
304+
| P2748R5: [返却された左辺値から暗黙変換された一時オブジェクトが参照に束縛されることを禁止する](/lang/cpp26/disallow_binding_a_returned_glvalue_to_a_temporary.md) | 寿命切れの変数によって引き起こされるバグを防止する | 14 | 19 | | |
305305
| P3106R1: [要素数不明の配列を集成体初期化する規則を明確化](/lang/cpp26/clarifying_rules_for_brace_elision_in_aggregate_initialization.md.nolink) | 配列要素の集成体初期化で`{}`が省略された場合の矛盾していた規定を修正 | yes | 17 | | |
306306
| P0609R3: [構造化束縛への属性を許可](/lang/cpp26/attributes_for_structured_bindings.md) | `auto [a, b [[maybe_unused]], c] = f();`のように構造化束縛の要素に対して属性を付加できるようにする | 15 | 19 | | |
307307
| P3034R1: [モジュール宣言でのモジュール名のマクロ展開を禁止する](/lang/cpp26/module_declarations_shouldnt_be_macros.md) | `export module MACRO_NAME;`を禁止 | | | | |

lang/cpp26.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ C++26とは、2026年中に改訂される予定の、C++バージョンの通
1414
| [`std::initializer_list`の配列を静的記憶域に配置する](/lang/cpp26/static_storage_for_braced_initializers.md) | `std::vector v = {1, 2, 3};`のような初期化で初期化子リストを静的記憶域に配置することで無駄なコピーをなくす |
1515
| [宣言のみで使用しない変数の名前として`_`をサポート](/lang/cpp26/nice_placeholder_with_no_name.md) | 変数名`_`は暗黙で`[[maybe_unused]]`が指定される |
1616
| [不完全型へのポインタに対する`delete`を不適格とする](/lang/cpp26/deleting_a_pointer_to_an_incomplete_type_should_be_ill-formed.md) | 未定義動作を引き起こす操作をコンパイルエラーとする |
17-
| [返却された左辺値から暗黙変換された一時オブジェクトが参照に束縛されることを禁止する](/lang/cpp26/disallow_binding_a_returned_glvalue_to_a_temporary.md.nolink) | 寿命切れの変数によって引き起こされるバグを防止する |
17+
| [返却された左辺値から暗黙変換された一時オブジェクトが参照に束縛されることを禁止する](/lang/cpp26/disallow_binding_a_returned_glvalue_to_a_temporary.md) | 寿命切れの変数によって引き起こされるバグを防止する |
1818
| [要素数不明の配列を集成体初期化する規則を明確化](/lang/cpp26/clarifying_rules_for_brace_elision_in_aggregate_initialization.md.nolink) | 配列要素の集成体初期化で`{}`が省略された場合の矛盾していた規定を修正 |
1919
| [未初期化変数の読み取りをエラー性動作とする](/lang/cpp26/erroneous_behavior_for_uninitialized_reads.md) | 初期化されていない自動変数の読み取りの安全性を規定する |
2020
| [構造化束縛でパックを導入できるようにする](/lang/cpp26/structured_bindings_can_introduce_a_pack.md) | タプルを分解する際に複数の変数をパックとして宣言できるようにする。`auto [a, ...xs] = f();` |
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# 返却された左辺値から暗黙変換された一時オブジェクトが参照に束縛されることを禁止する [P2748R5]
2+
* cpp26[meta cpp]
3+
4+
<!-- start lang caution -->
5+
6+
このページはC++26に採用される見込みの言語機能の変更を解説しています。
7+
8+
のちのC++規格でさらに変更される場合があるため関連項目を参照してください。
9+
10+
<!-- last lang caution -->
11+
12+
## 概要
13+
C++26では、暗黙変換された一時オブジェクトが参照に束縛されることを禁止し、寿命切れした変数を参照し続けることによるバグを防止する。
14+
15+
例として、以下のコードには一時オブジェクトを参照するバグが存在する。
16+
17+
```cpp
18+
struct X {
19+
const std::map<std::string, int> d_map;
20+
const std::pair<std::string, int>& d_first;
21+
22+
X(const std::map<std::string, int>& map)
23+
: d_map(map), d_first(*d_map.begin()) {}
24+
};
25+
```
26+
27+
ここで、[`std::map`](/reference/map/map.md)の先頭要素を式`d_first(*d_map.begin())`でメンバ変数に保持しようとしているが、先頭要素の実際の型は`std::pair<const std::string, int>`であり、`std::pair<std::string, int>`への暗黙変換によって一時オブジェクトが作られてしまっている。そのため、コンストラクタの終了時にその一時オブジェクトの寿命が終了し、メンバ変数`d_first`は寿命切れした変数を参照してしまっている。
28+
29+
このようなコードは初学者だけでなく経験者も書いてしまい危険であるため、禁止する。
30+
31+
32+
## 仕様
33+
- C++23までの仕様:
34+
- 「関数のreturn文で返される値に束縛された一時オブジェクトの寿命は延長されない。一時オブジェクトは、return文の完全な式の終了時に破棄される」
35+
- C++26の仕様:
36+
- 「戻り値の型が参照である関数において、返された参照を一時オブジェクトに束縛するreturn文は不適格である」
37+
38+
```cpp
39+
auto&& f1() {
40+
return 42; // C++26: 不適格
41+
}
42+
43+
const double& f2() {
44+
static int x = 42;
45+
return x; // C++26: 不適格
46+
}
47+
48+
auto&& id(auto&& r) {
49+
return static_cast<decltype(r)&&>(r);
50+
}
51+
auto&& f3() {
52+
return id(42); // OKだが、バグの可能性がある
53+
}
54+
```
55+
56+
57+
## 参照
58+
- [P2748R5 Disallow Binding a Returned Glvalue to a Temporary](https://open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2748r5.html)
59+

0 commit comments

Comments
 (0)