2013-06-27 3 views
2

Я не возражаю против результата приведенного ниже кода, так как я считаю правильным предположить, что ссылка на константу lvalue и ссылку на rvalue продлевают время жизни временного объекта, возвращаемого функцией. Что меня удивляет этот пункт в Стандарте, который, кажется, говорят об обратном:Что мне недостает в стандарте C++ 11?

12.2p5 (курсив мой):

Второй контекст, когда ссылка связана с временным. временно, к которому ссылка привязана или временное, что является полным объектом подобъекта, к которому ссылка привязана сохраняется в течение всего срока ссылки кроме:

  • ...
  • ...
  • Срок службы временной привязки к возвращаемому значению в функции оператором возврата (6.6.3) является не extended; временное уничтожается в конце полного выражения в операторе return.

Пример кода:

#include <iostream> 

struct A{ A() : i(2) {} int i;}; 

A f() { A a; return a; } 

int main() 
{ 
    A&& a1 = f(); 
    std::cout << a1.i << '\n'; 
    const A& a2 = f(); 
    std::cout << a2.i << '\n'; 
} 
+3

Я не понимаю, каков ваш вопрос. Какой результат вы получаете от своей программы? Что неожиданно? Какую версию компилятора вы тестируете? –

+9

'A const & f() {return A(); } ' – Xeo

+2

Я не думаю, что указанная вами точка маркера относится к вашему примеру. Я считаю, что это относится к чему-то вроде «return ;», не присваивая возвращаемое значение функции ссылке. –

ответ

4

Второй контекст, когда ссылка связан с временным - исключением - Срок службы временной предел для возвращаемого значения в функции обратного утверждения не продлен

A f() { A a; return a; } 

Прежде всего, a не является временным. Возможно, это было то, о чем вы думали:

A f() { return A(); } 

Во-вторых, возвращаемый тип функции не является ссылочным типом.Вот когда будет применяться правило:

const A& f() { return A(); } 

Временный из A() в настоящее время связан с типом возвращаемого const A&. В соответствии с правилом срок жизни временного не продлевается.

+0

Когда я читаю третью точку маркера в 12.2p5, я не вижу, как она относится к случаю 'A const & f() {return A(); } ', хотя я считаю, что это правильный ответ. Не могли бы вы объяснить это? – Belloc

+0

@ user1042389: Таким образом, оператор 'return EXPR' вызывает возвращаемое значение функции для инициализации с выражением' EXPR'. Возвращаемое значение имеет тип возвращаемой функции. Я не уверен, что конкретно вы не понимаете. –

5

цитата вы упоминаете специально для возвращения ссылки из функции и привязки, что ссылка на временный:

const T& f() { return T(); }; 

Это не является в вашем коде, потому что вы привязываете временную ссылку на сторону вызова, а не в оператор return. В комментариях вы упоминаете, что при изменении кода на:

T f() { return T(); } 
T&& r = f(); 

срок службы еще продлен, но это не так. Временные жизни в течение срока действия оператора return, во время которого он копируется в возвращаемое значение. После того, как копия завершает время жизни временных концов. На вызывающей стороне у вас разные временные (результат f()), срок жизни которых увеличивается.

Но нет сомнений в том, что продолжительность жизни временных линий продлена. Если вы определяете деструктор для класса A с любым сообщением, он будет напечатан в конце main() или есть?

Это утверждение неверно. Вы видите эффекты оптимизации возвращаемого значения (RVO). Вместо того, чтобы создавать временное значение для T() внутри функции, а другое для возвращаемого значения, компилятор создает два объекта в одном месте. Вероятно, вы видите единственный объект на выходе программы, но в теории есть два.

Вы можете попробовать использовать g ++ с -fno-elide-constructors, и вы сможете увидеть оба временных файла, один из которых расширен, другой не будет.

В качестве альтернативы, вы можете вернуть ссылку:

const A& f() { return A(); } 
const A& r = f(); 

Который должен показать, как временные штампы до r выходит из области видимости.


Это в основном тот же самый тест ингибирования

$ г ++ --version | голова -1

г ++ (GCC) 4.3.2

$ кошка x.cpp

#include <iostream> 

struct X { 
    X() { std::cout << "X\n"; } 
    ~X() { std::cout << "~X\n"; } 
}; 

X f() { return X(); } 

int main() { 
    const X& x = f(); 
    std::cout << "still in main()\n"; 
} 

$ г ++ -o t1 x.cpp & & ./t1

X 
still in main() 
~X 

$ г ++ -fno-Elide-конструкторов -o t2 x.cpp & & ./t2

X 
~X 
still in main() 
~X 

$ лязг ++ -версия | голова -1

$ лязг версия 3.2 (теги/RELEASE_32/конечный)

$ лязг ++ -fno-Elide-конструкторов -o t3 x.cpp & & ./t3

X 
~X 
still in main() 
~X 

$ кошка y.cpp

#include <iostream> 

struct X { 
    X() { std::cout << "X\n"; } 
    ~X() { std::cout << "~X\n"; } 
}; 

const X& f() { return X(); } 

int main() { 
    const X& x = f(); 
    std::cout << "still in main()\n"; 
} 

$ г ++ -fno-Elide-конструкторов -o t4 y.cpp & & ./t4

X 
~X 
still in main() 
+0

Временные матрицы еще до инициализации 'r'. Что бы вы ни выбрали из 'f()', это уже болтающаяся ссылка. Также вы уверены в 'T & f()'? Отсутствует 'const' или' & 'там? – Xeo

+0

В фрагменте нет возможности для RVO, так как функция возвращает именованный объект. – Belloc

+2

@ user1042389 * Именованный * Оптимизация возвращаемого значения (NRVO) хотела бы поговорить с вами. – Xeo