кейс.

о обоснование дизайна, позволяющее это

const Foo& a = function_returning_Foo_by_value();

но не это

Foo& a = function_returning_Foo_by_value();

?

Что может пойти не так во второй строке (что уже не пойдет не так в первой строке)?

 Matthieu M.12 янв. 2011 г., 16:47
@DumbCoder: нет, Херб Саттер разрабатывает использование по отношению к стандарту C ++, в то время как Фред обсуждает обоснование этого стандарта.
 DumbCoder12 янв. 2011 г., 16:31
Разве это не тот же вопрос, который обсуждал Херб Саттер здесь?herbsutter.com/2008/01/01/... ?

Ответы на вопрос(4)

ожидается, что временное устройство будет уничтожено, когда оно выйдет за рамки.Если вы обещаете не изменять его, я позволю вам продлить его жизнь.

Решение Вопроса

Почему они позволилиFoo const& foo = fooByValue(); начать с ?

Это делает жизнь (несколько) легче, но повсюду вводит потенциальное неопределенное поведение.

Foo const& fooByReference()
{
  return fooByValue(); // error: returning a reference to a temporary
}

Это, очевидно, неправильно, и действительно, компилятор покорно сообщит об этом.Согласно комментарию Томалака: стандарт не обязателен, но хорошие компиляторы должны сообщать об этом. Clang, GCC и MSVC делают. Я думаю, что Comeau и ICC тоже.

Foo const& fooByIndirectReference()
{
  Foo const& foo = fooByValue(); // OK, you're allowed to bind a temporary
  return foo;                    // Generally accepted
}

Это неправильно, но более тонко. Проблема в том, что время жизни временного связано с временем жизниfoo, который выходит из области видимости в конце функции.копия изfoo передается вызывающей стороне, и эта копия указывает на эфир.

Я поднял ошибку на Clang, и Argyris смог диагностировать этот случай (на самом деле, слава: p).

Foo const& fooForwarder(Foo const&); // out of line implementation which forwards
                                     // the argument

Foo const& fooByVeryIndirectReference()
{
  return fooForwarder(fooByValue());
}

Временный созданныйfooByValue связан с временем существования аргументаfooForwarder, которые должным образом предоставляют копию (ссылки), копию, которая возвращается вызывающей стороне, даже если она теперь указывает на эфир.

Проблема в том, чтоfooForwarderРеализация совершенно прекрасна по отношению к стандарту, и все же она создает неопределенное поведение в вызывающей стороне.

Тем не менее, пугающим фактом является то, что для диагностики этого заболевания необходимо знать оfooForwarder, который недоступен для компилятора.

Единственное решение, которое я могу понять (кроме WPA), это решение во время выполнения: всякий раз, когда временная привязка привязана к ссылке, вам нужно убедиться, что возвращаемая ссылка не имеет один и тот же адрес ... и что потом?assert ? поднять исключение? И поскольку это только решение времени выполнения, оно явно не удовлетворительное.

Идея привязки временного к ссылке является хрупкой.

 Matthieu M.14 янв. 2011 г., 13:47
@ Томалак: Я исправлю, об этом сообщают по крайней мере MSVC, gcc и Clang, и я думаю, что Comeau и icc, вероятно, тоже.
 Lightness Races in Orbit14 янв. 2011 г., 11:54
«Это, очевидно, неправильно, и действительно, компилятор покорно сообщит об этом», если вам повезет, если у вас есть набор инструментов, который делает это, если ваши предупреждения установлены на определенный уровень и т. Д. И т. Д. Язык C ++ не требует диагностики для этот случай.

«Что может пойти не так» - это то, что вы модифицируете объект, а затем мгновенно теряете изменения, и поэтому определяется правило, помогающее вам не совершать таких ошибок. что если бы вы снова вызвали функцию, вы бы получили объект с вашими изменениями, чего, конечно, не получилось бы, потому что вы изменили копию.

Типичный случай, когда вы создаете временный, а затем вызываете неконстантный метод, это когда вы собираетесь его поменять:

std::string val;
some_func_that_returns_a_string().swap( val );

Иногда это может быть очень полезно.

 fredoverflow12 янв. 2011 г., 16:09
Почему я потерял бы изменения? Посмотрите на заголовок моего вопроса, временный будет жить до тех пор, покаaтак же, как это происходит вconst Foo& кейс.

что неконстантные указатели не продлевают срок службы временных файлов, заключается в том, что неконстантные ссылки не могут быть привязаны к временным файлам.

Есть много причин для этого, я просто покажу один классический пример, включающий неявные расширяющиеся преобразования:

struct Foo {};
bool CreateFoo( Foo*& result ) { result = new Foo(); return true; }

struct SpecialFoo : Foo {};
SpecialFoo* p;
if (CreateFoo(p)) { /* DUDE, WHERE'S MY OBJECT! */ }

Основанием для разрешения ссылок на const для временных привязок является то, что он обеспечивает совершенно разумный код, подобный этому:

bool validate_the_cat(const string&);

string thing[3];
validate_the_cat(thing[1] + thing[2]);

Обратите внимание, что в этом случае продление срока службы не требуется.

 Puppy12 янв. 2011 г., 16:11
Проблема, которую демонстрирует этот код, состоит в том, что значения не должны привязываться к обычным ссылкам. Это не демонстрирует, почему rvalues ​​должны связываться с константными ссылками. Любящий чувак, где мой объект :)
 David Rodríguez - dribeas12 янв. 2011 г., 23:16
Виноват! Я должен быть более осторожным ... Я имел интуицию и проверял, но я выполнил неправильный тест. Ты прав. Я удалил комментарий, где я себя одурачил :) +1
 Ben Voigt12 янв. 2011 г., 17:38
@David:const Foo*& не является постоянной ссылкой. Вы имеете в видуFoo* const&?
 Chris Drew04 мая 2017 г., 13:56
@ JeskoHüttenhain Это ссылка на указатель, а не указатель на ссылку. Можно ожидать, что ссылка на указатель будет использоваться для переустановки указателя и его замены выделенным объектом.
 Jesko Hüttenhain04 мая 2017 г., 18:52
А ну понятно. Мне нужно лучше читать типы C ++. Ну, тогда да, это на самом деле отличный пример.

Ваш ответ на вопрос