【发布时间】:2020-04-10 02:38:55
【问题描述】:
想象一下我们有:
struct S {
struct S {
S() { printf("%s\n", __PRETTY_FUNCTION__); }
S(const S&) { printf("%s\n", __PRETTY_FUNCTION__); }
S(S&&) { printf("%s\n", __PRETTY_FUNCTION__); }
~S() { printf("%s\n", __PRETTY_FUNCTION__); }
S(std::initializer_list<S>) { printf("%s\n", __PRETTY_FUNCTION__); }
};
S s2{S{}};
时应该调用哪些构造函数?
gcc和clang有不同的行为可以吗?
示例:https://godbolt.org/z/qQxyp5
gcc(主干)输出:
S::S()
S::S(std::initializer_list<S>)
S::~S()
S::~S()
clang(主干)输出:
S::S()
S::~S()
【问题讨论】:
-
这两种行为在技术上都是正确的,但 clang 的更优化。 gcc 在内部字符串上执行value-initialization,然后在外部字符串上执行list-initialization。 clang 看到
s2
是由临时内部字符串和elides the temp away 构造的,直接构造s2
。见When and why would I use -fno-elide-constructors? -
godbolt 链接是一个很好的补充,但在问题中包含输出使其自包含链接是否有效。而且我不必单击链接并尝试找出该页面的相关部分。
-
@RemyLebeau:“clang 看到 s2 是由一个临时内部字符串构造的,并忽略了临时”我在标准中看不到任何允许这样的省略。 C++17 中的保证省略基于用于初始化对象的纯右值,但列表初始化违反了这一点,因为对于类类型,它会触发第 3.6 节,即调用构造函数。并且省略的通用规则不会列出从纯右值初始化列表的情况作为省略的可能情况。