从函数返回的对象的延长生命周期
Extended lifetime of an object returned from function
关于从函数 return 编辑并绑定到 rvalue/const 左值引用的对象生命周期的延长,我有一些不清楚的信息。来自 here.
的信息
a temporary bound to a return value of a function in a return statement is not extended: it is destroyed immediately at the end of the return expression. Such function always returns a dangling reference.
如果我理解正确,引用声称对象的生命周期 returned by return statements 是不可延长的。但最后一句话表明,这仅适用于 returning 引用的函数。
在 GCC 上,此代码产生以下输出:
struct Test
{
Test() { std::cout << "creation\n"; }
~Test() { std::cout << "destruction\n"; }
};
Test f()
{
return Test{};
}
int main()
{
std::cout << "before f call\n";
Test && t = f();
std::cout << "after f call\n";
}
before f call
creation
after f call
destruction
看来寿命延长了。
是否应该延长绑定到此类引用的临时对象的生命周期?另外能否提供更明确的信息来源?
引用自GOTW article
A temporary object lasts only until the end of the full expression in which it appears. However, C++ deliberately specifies that binding a temporary object to a reference to const (or ravlue reference) on the stack lengthens the lifetime of the temporary to the lifetime of the reference itself, and thus avoids what would otherwise be a common dangling-reference error.
string f() { return "abc"; }
void g() {
const string& s = f();
cout << s << endl; // can we still use the "temporary" object?
}
In the example above, the temporary returned by f() lives until the closing curly brace. (Note this only applies to stack-based references. It doesn’t work for references that are members of objects.)
对于法律术语,请阅读 this SO answer
答案适用于局部常量引用和右值引用
So it looks like the lifetime got extended.
代码非常有效,但请注意,生命周期延长的对象不是Test{}
在函数f()
中创建的临时对象,它是函数[=]返回的对象13=]。返回的对象是从临时对象移动构造的,然后绑定到 t
并且生命周期得到延长。顺便说一句,返回的对象是按值返回的,它也是一个临时对象。
为了观察,您可以手动添加移动构造函数:
struct Test
{
Test() { std::cout << "creation\n"; }
~Test() { std::cout << "destruction\n"; }
Test(Test&&) { std::cout << "move\n"; }
};
并用禁止copy elision模式编译和运行,结果是:
before f call
creation // the temporary created inside f
move // return object move-constructed
destruction // the temporary destroyed
after f call
destruction // the returned object destroyed
引用标准,§15.2/6 Temporary objects [class.temporary]:
The temporary to which the reference is bound or the temporary that is
the complete object of a subobject to which the reference is bound
persists for the lifetime of the reference except:
(6.1) A temporary object bound to a reference parameter in a function
call persists until the completion of the full-expression containing
the call.
(6.2) The lifetime of a temporary bound to the returned value in a
function return statement is not extended; the temporary is destroyed
at the end of the full-expression in the return statement.
(6.3) A temporary bound to a reference in a new-initializer persists
until the completion of the full-expression containing the
new-initializer. [ Example:
struct S { int mi; const std::pair<int,int>& mp; };
S a { 1, {2,3} };
S* p = new S{ 1, {2,3} }; // Creates dangling reference
— end example ] [ Note: This may introduce a dangling reference, and
implementations are encouraged to issue a warning in such a case.
— end note ]
关于从函数 return 编辑并绑定到 rvalue/const 左值引用的对象生命周期的延长,我有一些不清楚的信息。来自 here.
的信息a temporary bound to a return value of a function in a return statement is not extended: it is destroyed immediately at the end of the return expression. Such function always returns a dangling reference.
如果我理解正确,引用声称对象的生命周期 returned by return statements 是不可延长的。但最后一句话表明,这仅适用于 returning 引用的函数。
在 GCC 上,此代码产生以下输出:
struct Test
{
Test() { std::cout << "creation\n"; }
~Test() { std::cout << "destruction\n"; }
};
Test f()
{
return Test{};
}
int main()
{
std::cout << "before f call\n";
Test && t = f();
std::cout << "after f call\n";
}
before f call
creation
after f call
destruction
看来寿命延长了。
是否应该延长绑定到此类引用的临时对象的生命周期?另外能否提供更明确的信息来源?
引用自GOTW article
A temporary object lasts only until the end of the full expression in which it appears. However, C++ deliberately specifies that binding a temporary object to a reference to const (or ravlue reference) on the stack lengthens the lifetime of the temporary to the lifetime of the reference itself, and thus avoids what would otherwise be a common dangling-reference error.
string f() { return "abc"; }
void g() {
const string& s = f();
cout << s << endl; // can we still use the "temporary" object?
}
In the example above, the temporary returned by f() lives until the closing curly brace. (Note this only applies to stack-based references. It doesn’t work for references that are members of objects.)
对于法律术语,请阅读 this SO answer
答案适用于局部常量引用和右值引用
So it looks like the lifetime got extended.
代码非常有效,但请注意,生命周期延长的对象不是Test{}
在函数f()
中创建的临时对象,它是函数[=]返回的对象13=]。返回的对象是从临时对象移动构造的,然后绑定到 t
并且生命周期得到延长。顺便说一句,返回的对象是按值返回的,它也是一个临时对象。
为了观察,您可以手动添加移动构造函数:
struct Test
{
Test() { std::cout << "creation\n"; }
~Test() { std::cout << "destruction\n"; }
Test(Test&&) { std::cout << "move\n"; }
};
并用禁止copy elision模式编译和运行,结果是:
before f call
creation // the temporary created inside f
move // return object move-constructed
destruction // the temporary destroyed
after f call
destruction // the returned object destroyed
引用标准,§15.2/6 Temporary objects [class.temporary]:
The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference except:
(6.1) A temporary object bound to a reference parameter in a function call persists until the completion of the full-expression containing the call.
(6.2) The lifetime of a temporary bound to the returned value in a function return statement is not extended; the temporary is destroyed at the end of the full-expression in the return statement.
(6.3) A temporary bound to a reference in a new-initializer persists until the completion of the full-expression containing the new-initializer. [ Example:
struct S { int mi; const std::pair<int,int>& mp; }; S a { 1, {2,3} }; S* p = new S{ 1, {2,3} }; // Creates dangling reference
— end example ] [ Note: This may introduce a dangling reference, and implementations are encouraged to issue a warning in such a case. — end note ]