2026-09-07
holder.cpp
#include <iostream>
#include <string>
struct Holder {
const std::string &ref;
Holder(const std::string &s) : ref(s) {}
};
std::string make_greeting() {
return "hello";
}
int main() {
Holder h(make_greeting());
std::cout << h.ref << "\n"; // undefined behavior
}
h.refはダングリング参照になっており、これを使うのは未定義動作です。以前扱った「ローカル変数へのconst参照は寿命が延長される」規則があるのに、なぜここでは延長されないのでしょうか?どう直せばよいですか?
Answer
一時オブジェクトの寿命延長は、参照変数がその一時オブジェクトに直接束縛されたときにだけ働きます。make_greeting()が返す一時オブジェクトが直接束縛されるのはコンストラクタの引数sであり、sの寿命はHolderのコンストラクタ呼び出しが終わるまでです。メンバ初期化子ref(s)はsと同じものを指すようにするだけで、一時オブジェクトの寿命をさらにhの寿命まで延ばしてはくれません。結果、コンストラクタが戻った時点で一時オブジェクトは破棄され、h.refはダングリング参照として残ります。最小限の修正は、参照ではなく値としてメンバを持つことです:
struct Holder {
std::string ref;
Holder(const std::string &s) : ref(s) {}
};