[英]C++ temporary object bound to argument and return value const references
即使在查閱SO上的相關問題並閱讀C ++ 03標准頁面192( http://cs.nyu.edu/courses/fall11/CSCI-GA.2110)之后,我也無法清楚地知道這是否合法。 -003 / documents / c ++ 2003std.pdf )。 這是合法和安全的:
const MyClass& f(const MyClass& arg) {
return arg;
}
void some_other_function() {
const MyClass& reference = f(MyClass());
// Use reference.
}
在我看來它是。
據我所知,你不能這樣做。 雖然將臨時綁定到const引用是合法的C ++(並且延長了該臨時的生命周期 - 請參閱GOTW 88 ),將const ref與另一個const ref進一步綁定並不會延長該臨時值的生命周期。
第192頁的引用( C ++ 03標准 ):
在函數調用(5.2.2)中與引用參數的臨時綁定將持續存在,直到包含該調用的完整表達式完成為止
我認為標准非常明確,在使用引用之后// Use reference.
是無效的。 我修改了你的代碼片段來檢查它(Mac OS X,clang: Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
):
#include <iostream>
struct MyClass
{
~MyClass()
{
std::cout << "~MyClass()" << std::endl;
}
};
const MyClass& f(const MyClass& arg) {
std::cout << "f()" << std::endl;
return arg;
}
int main() {
const MyClass& reference = f(MyClass());
std::cout << "main()" << std::endl;
}
它輸出:
f()
~MyClass()
main()
換句話說,除非我和clang開發人員都誤解了C ++標准,否則它是非法的。
我無法從標准中得到明確的解釋,所以我決定檢查什么是事實上的標准。 以下代碼:
#include <cstdio>
struct MyClass
{
MyClass() { printf("constructor\n"); }
~MyClass() { printf("destructor\n"); }
MyClass(const MyClass&) { printf("copy\n"); }
MyClass(MyClass&&) { printf("move\n"); }
};
const MyClass& f(const MyClass& arg) {
return arg;
}
int main()
{
{
printf("before construction\n");
const MyClass& reference = f(MyClass());
printf("after construction\n");
}
printf("outside scope\n");
}
產量:
before construction
constructor
destructor
after construction
outside scope
對於MSVC,clang和g ++。 根據我們的主要編譯器供應商,它似乎不合法。
這個問題類似於以下問題:將const const_Type&傳遞給std :: map的operator []
下面的代碼解釋了究竟發生了什么
#include <iostream>
struct MyClass{
int member;
MyClass():member(0){
std::cout<<"MyClass ctr "<<std::endl;
}
MyClass(const MyClass& rhs){
std::cout<<"MyClass copy ctr "<<std::endl;
}
~MyClass(){
std::cout<<"MyClass dtr"<<std::endl;
member = -1;
}
};
void f2(const MyClass& obj){
std::cout<<"func "<<obj.member<<std::endl;
}
const MyClass& f3(){
return MyClass();
}
MyClass f4(){
return MyClass(); //ideally not a good idea, exception is
//http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/
}
int main()
{
std::cout << "-----Faulty Case-----------"<<std::endl;
//reference returned by f3 is local to f3 call and
//is destructed as soon as f3() is out of stack
//and hence the reference in f2() is not valid
f2( f3() );
std::cout <<std::endl<< "-----Correct way-----------"<<std::endl;
//A temporary object is returned by f4 which is then referred by reference in f2.
//This reference is alive in stack of f2 and hence can be used inside
//f2 with valid results.
//As explained in following article, the refernce should remain
//alive in stack to use temporary objects.
//http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/
f2( f4() );
//note in previous expression, f4 returns by value but still copy ctr is not invoked,
//this I believe is Return Value Optimization (might be compiler dependent)
return 0;
}
該計划的產出將是:
Executing the program....
$demo
-----Faulty Case-----------
MyClass ctr
MyClass dtr
func -1
-----Correct way-----------
MyClass ctr
func 0
MyClass dtr
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.