Сделайте * non * -const ссылки продлить жизнь временные?

Когда-то я предполагал, что такой код не сработает:

const MyClass& obj = MyClass();
obj.DoSomething();

потому что объект MyClass будет уничтожен в конце его полного выражения, оставив obj в качестве висячей ссылки. Однако я узнал (здесь), что это не так; на самом деле стандарт имеет специальное положение, которое позволяет ссылаться на константные ссылки, чтобы поддерживать временные ресурсы до тех пор, пока указанные ссылки не будут уничтожены сами. Но, было подчеркнуто, только эта константа имеет эту силу. Сегодня я провел код в VS2012 в качестве эксперимента.

struct Foo
{
    Foo() { std::cout << "ctor" << std::endl; }
    ~Foo() { std::cout << "dtor" << std::endl; }
};

void f()
{
    Foo& f = Foo();
    std::cout << "Hello world" << std::endl;
}

Вывод при вызове f() был:

ctor  
Hello world  
dtor  

Итак, я посмотрел проект стандарта С++ 11 и нашел это (§ 12.2/4):

Существует два контекста, в которых временные другая точка, чем конец полного выражения. Первый контекст [не подать выражение]. Второй контекст - это когда ссылка привязана к временный характер. Временное, к которому привязана ссылка, или временный, который является полным объектом подобъекта, которому ссылка привязана для времени жизни ссылки.

Слово const явно отсутствует в приведенном выше. Так; это поведение было изменено для С++ 11, был ли я ошибочным в отношении вещи const для начала или у VS2012 есть ошибка, и я просто не нашел соответствующую часть стандарта?

Ответ 1

Поведение не изменилось, вам просто нужно увеличить уровень предупреждения до /W4. VisualStudio реализует правило расширения продолжительности жизни даже для ссылок const lvalue как расширение компилятора. В этом контексте привязка значения r к ссылке не const ведет себя так же, как если бы вы привязывали ее к справочнику const.

С /W4 вы увидите следующее:

warning C4239: nonstandard extension used : 'initializing' : conversion from 'Foo' to 'Foo &'
1>  A non-const reference may only be bound to an lvalue

Текст, запрещающий привязку значения rval к ​​ссылочной ссылке не const, можно найти в § 8.5.3/5

— В противном случае эта ссылка должна быть ссылкой lvalue на нелетучий тип const (т.е. Cv1 должен быть const), или ссылка должна быть ссылкой rvalue.
[Пример:

  double& rd2 = 2.0; // error: not an lvalue and reference not const
  int i = 2;
  double& rd3 = i; // error: type mismatch and reference not const

-end пример]

Вторая половина цитируемого оператора - это то, что позволяет привязывать временную ссылку rvalue, как показано в litb answer.

string &&s = string("hello");

Это, в сочетании с правилом расширения продолжительности жизни в §12.2/5, означает, что время жизни временной воли теперь соответствует времени жизни ссылки (rvalue), к которой она привязана.

Ответ 2

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

Когда-то в конце 1980 года (очень предварительный), С++ представил правило, что временное не может использоваться для инициализации неконстантная ссылка. Инициализация неконстантной ссылки с временный по-прежнему продлевает срок службы (предположительно), но поскольку вы не могли этого сделать... Большинство компиляторов реализовано переходный период, в котором такая инициализация будет выдать предупреждение (и срок его жизни был расширен).

По какой-то причине Microsoft, наконец, решила реализовать С++ (некоторое время в начале 1990-х годов), они решили не выполнить новое правило и разрешить инициализацию неконстантная ссылка с временным (без предупреждения, в то время, когда большинство других поставщиков постепенно предупреждение в ошибке). И, конечно же, обычное правило жизни.

Наконец, в С++ 11 были введены новые типы ссылок, который позволил (или даже потребовал) инициализацию с временный. Правило о времени жизни временных изменено; временное, которое используется для инициализации ссылка (независимо от типа ссылки) имеет продолжительность жизни.

(За некоторыми исключениями: я бы не рекомендовал использовать временную для инициализации ссылки на элемент класса при инициализации список.)

Ответ 3

Нет, поскольку ссылки rvalue не должны быть const, поэтому стандартная цитата правильная

string &&s = string("hello");

Срок службы все еще увеличивается. Ограничения, которые делают код недействительным для ссылки non-const lvalue, приведены в разделе 8 (обратите внимание, что в указанном вами параграфе не так просто добавить "const" и "rvalue reference" и т.д. Вам нужно активное отклонение такие привязки, а не просто говорят о том, что время жизни таких привязок не увеличивается, потому что вы оставите привязку по-прежнему хорошо сформированной).