我做了以下小程序: (基本上是一个类,如果它被创建,复制或销毁,并且主要执行其中一些)
class Foo
{
public:
Foo(string name): _name(name)
{
cout << "Instance " << _name << " of Foo created!" << std::endl;
};
Foo(const Foo& other): _name(other._name)
{
cout << "Instance " << _name << " of Foo copied!" << std::endl;
};
~Foo()
{
cout << "Instance " << _name << " of Foo destroyed!" << std::endl;
}
string _name;
};
int main( int argc, char**argv)
{
Foo albert("Albert");
Foo bert("Bert");
{
vector<Foo> v1, v2;
system("PAUSE");
v1.push_back(albert);
system("PAUSE");
v2.push_back(bert);
system("PAUSE");
v1 = v2;
system("PAUSE");
}
system("PAUSE");
}
输出如下:
Instance Albert of class Foo created!
Instance Bert of class Foo created!
Press any key...
Instance Albert of class Foo copied!
Instance Albert of class Foo copied! // why another copy?
Instance Albert of class Foo destroyed! // and destruction?
Press any key...
Instance Bert of class Foo copied!
Instance Bert of class Foo copied!
Instance Bert of class Foo destroyed!
Press any key... // v1=v2 why did the albert instance not get destroyed?
Press any key...
Instance Bert of class A destroyed!
Instance Bert of class A destroyed!
Press any key... // there's still an albert living in the void
这让我非常奇怪。 如果它被复制两次,为什么我甚至不愿意传递一些东西作为参考呢? 为什么v1.operator =(other)不会破坏它包含的元素? 它很适合shared_ptr的行为。 有人可以告诉我为什么吗?
ADDITION 我把它放在一个无限循环中并检查内存使用情况,它似乎没有产生 至少是一个内存泄漏。
ADDITION 好吧,mem不是问题,因为它使用operator =而不是copy ctor,好的,谢谢。 当我添加
v1.reserve(10);
v2.reserve(10);
发生逻辑份数。没有它,它会为每一个push_back重新分配和复制整个向量,(即使对于小向量,我发现它也很迟钝)。 看看这个,我会考虑使用.reserve更多并优化我的赋值运算符如地狱:)
附加:摘要
答案 0 :(得分:4)
如果它被复制两次,为什么我甚至不愿意传递一些东西作为参考?
您应该将STL容器类型视为黑盒,可以根据需要随时复制存储的对象。例如,每次调整容器大小时,都会复制所有对象。
编译器的push_back()
实现可能使用临时额外副本。在我的机器上(Mac OS X上的gcc),push_back()
期间没有额外的副本(根据您的程序输出)。
此副本发生在STL代码中的某个位置,而不是在您的复制构造函数中(因为它使用了引用)。
为什么v1.operator =(other)不会破坏它包含的元素?
Foo::operator=
将以“bert”实例作为参数调用“albert”实例。因此,这里没有隐式的销毁和复制操作。您可能希望通过为运营商提供自己的实现来验证这一点:
Foo& operator=(const Foo& other) {
cout << "Instance " << other._name << " of Foo assigned to " << _name << "!" << std::endl;
return *this;
}
这会在我的机器上产生以下输出:
Foo的阿尔伯特创建了! Foo的实例Bert创建了!
Foo的阿尔伯特实例被复制了!
Foo的实例Bert被复制了!
Foo的实例Bert分配给Albert! Foo的实例Bert被摧毁!
Foo阿尔伯特被毁坏了!
Foo的实例Bert被摧毁!
Foo的阿尔伯特实例被毁了!
答案 1 :(得分:3)
有一个auto generated =运算符。当你使用v1 = v2运算符时。此时,其中一个“albert”实例变为“bert”。尝试将此功能添加到Foo:
Foo& operator = (const Foo& rval) {
cout << _name << " = " << rval._name << endl;
_name = rval._name;
return *this;
}
这与自动生成的相同,但打印出调试消息,以便您可以看到正在发生的事情。
答案 2 :(得分:1)
使用GCC编译时不会发生“双重复制”。这必须特定于在VC ++中实现std :: vector的方式。
答案 3 :(得分:1)
Visual Studio 2008为我提供了以下输出:
Instance Albert of Foo created! Instance Bert of Foo created! Press any key to continue . . . Instance Albert of Foo copied! Press any key to continue . . . Instance Bert of Foo copied! Press any key to continue . . . Press any key to continue . . . << here auto-generated operator= doing its job Instance Bert of Foo destroyed! Instance Bert of Foo destroyed! << this is Albert was originally Press any key to continue . . .
似乎std::vector
实施在VS2005中效果不是很好。