Каков срок службы временных объектов в диапазоне? - PullRequest
0 голосов
/ 01 января 2019

Рассмотрим этот класс:

class Foo
{
public:

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

    typedef std::vector<std::string> Words;

    const Words & words ()
    {
        return m_words;
    }

private:

    Words m_words = {"foo", "bar", "baz"};
};

Раздел 12.2 стандарта C ++ определяет время жизни временных объектов.Я думал, что все будет в порядке:

for (auto w : Foo () .words ())
    std::cout << w << "\n";

Но это не было

~Foo
terminate called after throwing an instance of 'std::logic_error'
  what():  basic_string::_M_construct null not valid
[1]    10290 abort (core dumped)  ./a.out

Стандарт меня смущает.Почему ~Foo вызывается до запуска цикла?

Ответы [ 2 ]

0 голосов
/ 01 января 2019

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

[class.teven] / 6 - Существуют три контекста, в которых временные объекты уничтожаются в другой точке, чем конец полного выражения.

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

Если вы измените выражение for-loop для привязки непосредственно к подобъекту m_words (при условии, что оно было общедоступным), то время жизни Foo() будет продлено, и будет работать следующее

for (auto w : Foo ().m_words)
    std::cout << w << "\n";
0 голосов
/ 01 января 2019

Текущий стандарт говорит в На основе диапазона для оператора [stmt.ranged] , что

На основе диапазона для оператора
for ( init-statementopt for-range-declaration : for-range-initializer ) оператор
эквивалентно

{
    init-statementopt
    auto &&__range = for-range-initializer ;
    auto __begin = begin-expr ;
    auto __end = end-expr ;
    for ( ; __begin != __end; ++__begin ) {
      for-range-declaration = *__begin;
      statement
    }
}

Это означает, что ваш Foo().words() используется только в присваивании auto &&__range = Foo().words(); и что временный объект не живет, пока код не достигнет цикла for.

Обратите внимание, что я скопировал с последней версии C ++ 20 .В C ++ 11 код немного отличается, но соответствующая часть та же самая.

...