Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/amazon-s3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ c++;:过度复制大型对象_C++_Copy Constructor_Assignment Operator - Fatal编程技术网

C++ c++;:过度复制大型对象

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 }; 所以你可以看到,我花在保存这些元数据上的

虽然关于SO上的复制构造函数/赋值运算符已经有很多问题,但我没有找到适合我的问题的答案

我有一门课

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++中非常容易(可能太容易)调用拷贝,但有一些方法可以避免不必要的复制:

  • 通过常量和非常量引用传递
  • 移动构造函数
  • 具有所有权转移的智能指针
这些技术可能只留下算法所需的副本


有时甚至可以避免一些复制。例如,如果您需要两个对象,其中第二个对象是第一个对象的反向副本,则可以创建一个包装器对象,该对象的行为类似于反向,但不是存储整个副本,而是只有一个引用。

一切都取决于复制此对象在您的情况下的含义:

  • 它意味着复制它的全部价值
  • 这意味着复制的对象将引用相同的内容
  • 如果是1,那么这个类看起来是正确的。你不太清楚你说的那些操作会产生很多副本,所以我假设你会复制整个对象

    如果是2,那么您需要使用类似shared_ptr的东西在对象之间共享容器。仅使用shared_ptr而不是真实对象作为成员将隐含地允许两个对象(拷贝和拷贝)引用缓冲区。 这是一种更简单的方法(使用boost::shared_ptr或std::shared_ptr,如果您有一个支持C++0x的编译器提供它的话)

    还有更困难的方法,但它们肯定会在以后成为一个问题

  • 当然,每个人都这么说,不要过早地优化。除非你证明a)你的程序运行得太慢,b)如果你不复制那么多数据,它会运行得更快,否则不要为此烦恼

  • 如果您的程序设计要求您同时保存多个数据副本,那么您将无能为力。你只要咬紧牙关复制数据就行了。不,实现自定义复制构造函数和自定义赋值运算符不会使它运行得更快

  • 如果您的程序不需要此数据的多个同时拷贝,那么您确实有一些技巧来减少执行的拷贝数

  • 使用你的复制方法如果是我,我会做的第一件事,甚至在尝试改进任何东西之前,就是数一数我的复制方法被使用的次数 调用

    运行您的程序,无论有无改进。打印出这些静态成员的值,以查看您的更改是否有任何影响

    <>强>避免使用引用<函数>函数调用中的赋值>。如果将FO类型的对象传递给函数,请考虑是否可以通过引用来完成。如果不更改传递的副本,那么通过const引用传递它是一件轻而易举的事情

    // 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);
        ...
    }