2017-02-07 13 views
3

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

#include <iostream> 

struct Test { 
    Test() { 
     std::cout << __PRETTY_FUNCTION__ << std::endl; 
    } 
    ~Test() { 
     std::cout << __PRETTY_FUNCTION__ << std::endl; 
    } 
}; 

struct Holder { 
    Holder(const Test& t):m_t(t) { 
     std::cout << __PRETTY_FUNCTION__ << std::endl; 
    } 
    ~Holder() { 
     std::cout << __PRETTY_FUNCTION__ << std::endl; 
    } 

    const Test& m_t; 
}; 

int main() { 
    Holder(Test()); 

    return 0; 
} 

Однако, я был весьма удивлен, увидев, что компилятор фактически оптимизированный все этот, как можно видеть на codebolt

Но, если я на самом деле дать имени к временный, изменив строку

Holder(Test()); 

в

Holder h((Test())); 

Тогда это «магически» работает: codebolt.

сюжетный поворот: при переходе на C++ 11 и использовать приготовилась инициализация списка для Holder класса, то конструктор не опущен независимо от того, даю ли я имя на временный или нет. См. Также codebolt.

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

Может ли кто-нибудь дать мне подсказку?

+2

'Держатель (Test());' - вариант наиболее неприятного разбора. – cpplearner

+0

О, черт! Думать, что я принял во внимание самый неприятный синтаксический разбор в том же примере, который я дал, с именованной переменной. –

+0

Это дополнительная пара круглых скобок, которая блокирует самый неприятный синтаксический разбор. 'Holder h (Test());' является самым неприятным анализом, 'Holder h ((Test())),' is not. – Oktalist

ответ

6

Это most vexing parse issue: Holder(Test()); объявляет функцию с именем Test, которая возвращает Holder и принимает 0 аргументов.

С г ++ следующий код:

#include <iostream> 
#include <type_traits> 

struct Test {}; 
struct Holder { Holder(Test); }; 

template<class T> 
char const* f() { return __PRETTY_FUNCTION__; } 

int main() { 
    Holder(Test()); 
    std::cout << f<decltype(&Test)>() << '\n'; 
} 

Выходы:

const char* f() [with T = Holder (*)()] 

легко исправить, чтобы использовать C++ 11 брекеты для инициализации: Holder(Test{}); или Holder{Test{}};.

+0

Хорошо, ах, это действительно меня достало. Я никогда не видел функцию, объявленную таким образом, я бы никогда не подумал, что это может быть объявление функции. Является ли это нежелательным побочным эффектом грамматики, или на самом деле оно использует? –

+1

@skypjack В стандарте C++ нет такой вещи, как _forward declaration_. См. _§3.1 Объявления и определения_. –

+0

@FabioA * "или он действительно использует?" * По * это *, вы ссылаетесь на разрешение круглых скобок вокруг имени функции и списка аргументов?Вам это нужно, по крайней мере, для объявления функции, которая возвращает указатель на функцию. – user2079303

 Смежные вопросы

  • Нет связанных вопросов^_^