C++ c++;:过度复制大型对象
虽然关于SO上的复制构造函数/赋值运算符已经有很多问题,但我没有找到适合我的问题的答案 我有一门课C++ c++;:过度复制大型对象,c++,copy-constructor,assignment-operator,C++,Copy Constructor,Assignment Operator,虽然关于SO上的复制构造函数/赋值运算符已经有很多问题,但我没有找到适合我的问题的答案 我有一门课 class Foo { // ... private: std::vector<int> vec1; std::vector<int> vec2; boost::bimap<unsigned int, unsigned int> bimap; // And a couple more }; 所以你可以看到,我花在保存这些元数据上的
class Foo
{
// ...
private:
std::vector<int> vec1;
std::vector<int> vec2;
boost::bimap<unsigned int, unsigned int> bimap;
// And a couple more
};
所以你可以看到,我花在保存这些元数据上的时间几乎和在图表中搜索的时间一样多。。哦,FooStore将Foo
保存在google::sparse\u hash\u map
中
编译器是g++4.4或g++4.5(我不在我的开发机器上,所以现在无法检查)
更新2我在构造后将一些成员分配给一个Foo实例,如
void SetVec1(const std::vector<int>& vec1) { this->vec1 = vec1; };
void SetVec1(const std::vector&vec1){this->vec1=vec1;};
我想明天,我应该改变这个使用交换方法,这肯定会改善这一点
我很抱歉,如果我不完全清楚我试图实现什么语义,但原因是我不太确定
问候,
莫顿你的课看起来没那么差,但你没有展示如何使用它 如果存在大量复制,则需要通过引用(或者如果可能的话,通过const引用)传递这些类的对象。
如果该类必须被复制,那么你就不能做任何事情。 如果它真的是一个问题,你可以考虑实现。但我怀疑这是一个问题,尽管我必须看到您对该类的使用情况才能确定。复制巨大的向量不太可能是便宜的。最有希望的方法是复制更稀有的。虽然C++中非常容易(可能太容易)调用拷贝,但有一些方法可以避免不必要的复制:
- 通过常量和非常量引用传递
- 移动构造函数
- 具有所有权转移的智能指针
有时甚至可以避免一些复制。例如,如果您需要两个对象,其中第二个对象是第一个对象的反向副本,则可以创建一个包装器对象,该对象的行为类似于反向,但不是存储整个副本,而是只有一个引用。一切都取决于复制此对象在您的情况下的含义:
// WAS:
extern SomeFuncton(Foo f);
// EASY change -- if this compiles, you know that it is correct
extern SomeFunction(const Foo& f);
// HARD change -- you have to examine your code to see if this is safe
extern SomeFunction(Foo& f);
<强>使用Fo::SWIFT 避免复制。如果使用大量复制方法(显式或隐式),请考虑所分配的项是否可以放弃它的数据,而不是复制它。
// Was:
vectorOfFoo.push_back(myFoo);
// maybe faster:
vectorOfFoo.push_back(Foo());
vectorOfFoo.back().swap(myFoo);
// Was:
newFoo = oldFoo;
// maybe faster
newfoo.swap(oldFoo);
当然,只有当myFoo
和oldFoo
不再需要访问它们的数据时,这才有效。而且,您必须实现Foo::swap
void Foo::swap(Foo& old) {
std::swap(this->vec1, old.vec1);
std::swap(this->vec2, old.vec2);
...
}
无论你做什么,在改变之前和之后衡量你的计划。测量您的复制方法被调用的次数,以及程序中的总时间改进。减少复制的明显方法是使用诸如共享ptr之类的工具。然而,使用多线程时,这种治疗方法可能比疾病更糟糕——增加和减少引用计数需要以原子方式进行,这可能非常昂贵。但是,如果您通常最终修改了副本,并且需要每个副本都具有唯一性(即,修改副本不会影响原始副本),那么最终可能会导致性能更差,需要为引用计数的原子增量/减量付费,并且仍然要执行大量副本 有几种明显的方法可以避免这种情况。一种是移动唯一的对象,而不是复制——如果你能让它工作的话,这很好。另一种方法是大部分时间使用非原子引用计数,只有在线程之间移动数据时才进行深度复制
没有一个答案是“一个通用的、真正干净的系统。复制会导致实际的性能问题吗?@Unaperson:他描述了它@莫顿:你是想为你的类提供浅层和深层复制构造函数吗?@Morten Jacobsen:你使用的编译器是什么版本?你需要展示你观察到过度复制的上下文。然后我们就能知道它是否是e
// Was:
vectorOfFoo.push_back(myFoo);
// maybe faster:
vectorOfFoo.push_back(Foo());
vectorOfFoo.back().swap(myFoo);
// Was:
newFoo = oldFoo;
// maybe faster
newfoo.swap(oldFoo);
void Foo::swap(Foo& old) {
std::swap(this->vec1, old.vec1);
std::swap(this->vec2, old.vec2);
...
}