我有一个Class Child,以及一个简单的向量推送实现,如下所示:
#include <stdio.h>
#include <vector>
#include <iostream>
class Child
{
public:
Child();
Child(const Child &item);
~Child();
};
Child::Child()
{
std::cout<<"Constructing Child\n";
}
Child::Child(const Child &item)
{
std::cout<<"Copy-Constructing Child\n";
}
Child::~Child()
{
std::cout<<"Destructing Child\n";
}
int main()
{
std::vector<Child> v;
Child Item1;
v.push_back(Item1);
}
在调用v.push_back( Item1 );
之后,我有以下输出:
Constructing Child
Copy-Constructing Child
Copy-Constructing Child
Destructing Child
我原以为Copy-Constructing Child
只会出现一次。为什么复制构造函数被调用两次?
答案 0 :(得分:1)
官方回答:对于你的班级,std :: vector可以随意制作任意数量的副本,因为标准中没有规定限制。
可能发生的事情:在将对象作为参数传递时进行复制,并在内部调整向量时再次进行复制。
效率不高吗?是
我该如何改进?
删除自定义析构函数和复制构造函数,或者定义自定义移动构造函数和复制运算符。前一种情况允许编译器创建自己的移动操作,后者提供它们。
一旦编译器推断出你的类是移动感知的,std :: vector的操作就会变得更有效率,你会看到一个副本(因为你强迫编译器通过命名{{1}来创建一个副本) } Child
}
编辑:考虑这个例子
Item1
示例输出:
#include <stdio.h>
#include <vector>
#include <iostream>
class Child
{
public:
Child();
Child(const Child &item);
Child(Child&& item);
Child& operator=(const Child &item);
Child& operator=(Child&& item);
~Child();
private:
std::string name() const {
return std::string { _zombie ? "zombie" : "child" };
}
bool _zombie = false;
};
Child::Child()
{
std::cout << "constructing " << name() << "\n";
}
Child::Child(const Child &item)
{
std::cout << "copy-constructing " << name() << "\n";
}
Child::Child(Child &&item)
{
std::cout << "move-constructing " << name() << "\n";
item._zombie = true;
}
Child& Child::operator=(const Child &item)
{
_zombie = false;
std::cout << "assigning " << name() << "\n";
return *this;
}
Child& Child::operator=(Child &&item)
{
item._zombie = true;
_zombie = false;
std::cout << "move-assigning " << name() << "\n";
return *this;
}
Child::~Child()
{
std::cout << "destructing " << name() << "\n";
}
using namespace std;
int main(int argc, const char * argv[])
{
{
std::vector<Child> v;
Child item1;
v.push_back(item1);
}
cout << endl;
{
std::vector<Child> v;
v.push_back(Child{});
}
cout << endl;
{
std::vector<Child> v;
Child item1;
v.push_back(std::move(item1));
}
cout << endl;
return 0;
}
答案 1 :(得分:1)
这种情况正在发生,因为您使用的是旧编译器。对不起,如果这不是一个非常令人兴奋的结论。 :-(没有其他人可以复制这个问题,即使在较新的微软编译器上也是如此。虽然理查德·霍奇斯认为编译器可以按照自己认为合适的方式自由复制,但现代编译器会尽力避免使用它们。你列出的情况,一个体面的编译器不应该复制,如果你担心性能,你应该考虑升级到更新的版本。