这是source.cpp
#include <iostream>
struct A {
A(int i) : i(i) { std::cout << this << ": A(int)" << std::endl; }
A(A const &a) : i(a.i) { std::cout << this << ": A(A const &)" << std::endl; }
A(A &&a) : i(a.i) { std::cout << this << ": A(A &&)" << std::endl; }
~A() { std::cout << this << ": ~A()" << std::endl; }
private:
int i;
};
int main() {
std::cout << "#1 :" << std::endl;
A a1 = 1; // #1, copy-initialization
std::cout << "#2 :" << std::endl;
A a3(1); // #2, direct-initialization
std::cout << "#3 :" << std::endl;
A a4 = {1}; // #3, copy-list-initialization
std::cout << "#4 :" << std::endl;
A a5{1}; // #4, direct-list-initialization
std::cout << std::endl;
return 0;
}
使用
clang++ -std=c++14 -Wall -fno-elide-constructors -pedantic -o main.exe source.cpp
编译以上代码(这里,我禁用了构造优化。顺便说一句,我正在使用Clang 3.8.1)。然后,我得到以下输出:#1 :
0x61fe40: A(int)
0x61fe48: A(A &&)
0x61fe40: ~A()
#2 :
0x61fe30: A(int)
#3 :
0x61fe28: A(int)
#4 :
0x61fe20: A(int)
0x61fe20: ~A()
0x61fe28: ~A()
0x61fe30: ~A()
0x61fe48: ~A()
让我惊讶的是,#3不会像#1那样先调用
A::A(int)
,然后再调用A::A(A &&)
,尽管它们都是复制初始化的。我还用gcc 6.1.0对其进行了测试。同样的事情发生。据我所知,列表初始化的一种常见用法是禁止缩小转换范围。我不知道它与编译优化有关。所以,使用列表初始化时,C++语言是否会强制执行编译器优化,或者只是编译器更喜欢这样做,还是其他原因导致了上述行为?
最佳答案
在这种情况下,直接和复制列表初始化都会导致对构造函数的调用。
使用[dcl.init.list] / 3中的规则中的消除过程,
带回家的重要一点是复制初始化和复制列表初始化是不等效的,您可以使用复制列表初始化来初始化带有已删除复制的对象,并移动例如构造函数:
struct A
{
A(int i){}
A(A const&) =delete;
A(A&&) =delete;
};
int main()
{
A a1 = {1};
A a2 = 1; // won't compile
}