为什么构造函数被忽略了这个未命名的临时文件,副作用是正常的初始化而不是支持列表初始化?

时间:2017-02-07 16:49:36

标签: c++11 constructor temporary c++98

我想测试一个临时对象是否至少与持有const引用的临时对象一样长,所以我想出了这个例子。

#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()));

然后它&#34;神奇地&#34;作品:codebolt

Plot twist :如果我切换到c ++ 11并使用Holder类的支撑列表初始化,那么无论我是否给出一个名称,构造函数都不会被省略暂时与否。再次查看codebolt

那么这里的问题是什么?我的印象是,副作用的构造函数永远不会被遗忘,但我显然错过了版本之间标准的重要部分。

任何人都可以给我一个提示吗?

1 个答案:

答案 0 :(得分:6)

这是most vexing parse issueHolder(Test());声明一个名为Test的函数,它返回Holder并接受0个参数。

使用g ++代码:

#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{}};