当我初始化 C++容器(例如 std::list)是否调用了复制构造函数?
当我初始化一个 STL 容器(例如 list
list<矢量
使用例如 my_list.push_back(vector
这是在构造后复制的吗?或者编译器是否调用 list
内的构造函数?矢量
本身?
When I initialize a STL container such as a list< vector<char> >
using e.g. my_list.push_back(vector<char>(5000, 'T'))
is this copied after construction? Or does the compiler invoke the constructor inside list< vector<char> >
itself?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在 C++03 中,
push_back
定义为void Push_back(const T& x);
。这意味着您正在构造一个向量,并且对此类时间的 const 引用将传递到列表。然后,list
在内部调用复制构造函数来存储此类元素的副本。在 C++11 中,有一个额外的
void Push_back(T&& x);
定义,它采用对时间向量
的右值引用,并会导致内部调用移动构造函数来初始化list
所保存的副本。In C++03
push_back
is defined asvoid push_back(const T& x);
. That means that you are constructing avector
and a const reference to such temporal is being passed to thelist
. Then thelist
internally invokes the copy constructor in order to store a copy of such element.In C++11 there is an extra definition for
void push_back(T&& x);
that takes an rvalue reference to your temporalvector
, and would result in the move constructor being called internally to initialize the copy held by thelist
.编译器很聪明。真的很聪明。在这种情况下,有一种称为“复制省略”的优化。 C++ 标准允许编译器在使用临时对象来初始化相同类型的对象时省略副本,并且该对象的复制构造函数没有副作用。
这与更流行的“好像”规则属于同一类优化。该规则允许编译器几乎可以摆脱它想要的任何东西,只要生成的程序的可观察行为与“就好像”完全遵循了标准一样。
这是一个示例程序。在 gcc 4.4.5 上,同时使用 -O0 和 -O3 时,此代码会打印“1”。我认为 GCC 在这里是错误的......一些编译器会输出“2”,表明发生了复制。这就是试图检测本应无法检测到的行为时变得棘手的地方。在其中一个编译器中,唯一的判断方法是深入研究生成的程序集。
Compilers are smart. Really smart. In this case, there is an optimization called "copy elision." The C++ standard allows the compiler to omit a copy when a temporary object is used to initialize an object of the same type and the copy constructor of said object has no side effects.
This is in the same class of optimizations as the more popular "as if" rule. That rule allows the compiler to get away with nearly anything it wants, as long as the observable behavior of the resulting program is the same "as if" the standard had been followed exactly.
Here is an example program. On gcc 4.4.5 with both -O0 and -O3 this code results in a "1" being printed. I think that GCC is wrong here... some compilers will output "2" indicating a copy took place. This is where things get tricky in trying to detect behavior that is supposed to be undetectable. In one of those compilers, the only way to tell will be to dive into the resulting assembly.