不可引用失效的临时对象
8.27 ID_referInvalidTmpObject
将临时对象与引用绑定可以延长临时对象的生命周期,但并不是在所有情况下都有效,应避免生命周期与预期不符造成的错误。
示例:
struct T {
string member = "abc";
string val() { return member; }
string& ref() { return member; }
string* ptr() { return &member; }
};
auto&& a = T(); // Compliant
auto&& b = T().member; // Compliant
auto&& c = T().val(); // Compliant
将纯右值与引用直接绑定可以使其生命周期与引用的生命周期保持一致。例中 T()、T().member、T().val() 均为纯右值,其生命周期可以被延长。
auto& x = T().ref(); // Non-compliant, dangling reference
auto* y = T().ptr(); // Non-compliant, dangling pointer
auto& z = T().member[0]; // Non-compliant, dangling reference
如果临时对象的成员函数返回成员的引用或地址,表达式执行完毕后临时对象析构,无法延长成员的生命周期。例中 x、z 为无效引用,y 为无效指针。
另外,构造函数初始化列表中的绑定不会延长临时对象的生命周期:
struct A {
const string& r;
A(): r("abc") {} // Non-compliant
A(const string& s): r(s) {}
};
A obj("123"); // Non-compliant
例中由 "abc" 创建的临时 string 对象在构造函数执行完毕后析构,由 "123" 创建的临时对象生命周期与参数 s 的生命周期相同,均无法正确初始化成员引用。
又如:
struct B { const string& r; };
B obj{"abc"};
B* ptr = new B{"123"}; // Non-compliant
如果不通过构造函数直接进行列表初始化,可以将临时对象与成员引用绑定,但 new 表达式中的临时对象与动态创建的对象具有不同的存储期,故不能保证可以正常绑定。总之,为了避免意料之外的错误并提高兼容性,不应将临时对象与成员引用绑定。
相关
依据
ISO/IEC 14882:2011 12.2(4 5)
ISO/IEC 14882:2017 15.2(5 6)