跨两个类的C ++ std :: vector优化

时间:2017-08-07 14:13:27

标签: c++ class vector

class B
{
public:
    std::vector< std::vector<int> > vec;

    void AtoB(const std::vector<int> &v)
    {
        vec.push_back(v);
    }
}

上面的B类保存数据。

class A
{
public:
    B* pSomeB;

    void fnA()
    {
        std::vector<int> v;
        for(int i = 0; i < 100; ++i)
        {
            v.push_back(rand());
        }

        pSomeB->AtoB(v);
    }

    void fnB()
    {
        pSomeB->push_back(std::vector<int>());

        std::vector<int> &v(pSomeB->vec[pSomeB->vec.size()-1]);
        for(int i = 0; i < 100; ++i)
        {
            v.push_back(rand());
        }
    }
  }

A类有一个指向Struct B实例的指针.A :: fnA()和A :: fnB()以不同的方式实现它。

如果我们调用fnA,则向量在本地构造,然后由ref传递,然后复制到B :: vec中。如果我们调用fnB它会获取对插入到vecB中的向量的引用,所以我们超出了我们的范围,但是我们绕过了构造和复制的需要,并将其构造到目标中。

现在,班级设计标准从纯粹的理论水平中剔除。那么fnB应该不是更有效率吗?如果矢量变大,特别明显?我很惊讶地看到fnB导致了一个相当大的可执行文件。如果有人对此有一些了解,那将非常有用!

编辑由于下面的有用评论我遗憾地必须指出std :: move不是一个选项,因为其中一个要求是项目代码在C ++ 0x之前工作/ C ++ 11

1 个答案:

答案 0 :(得分:0)

更正后,我将您的代码理解为fnB,试图直接修改B的向量,而不是通过fnA

进行相同的操作

如果您质疑:这样做效率更高吗? 答案是:它并没有破坏封装(A中的一个不应该看到B内部的内容,因为它阻止了以后更改B而不更改A

请注意,即使在fnB你正在创建一个空矢量,你也会重新分配2D数组({I}猜测你想要的push_back

因此,您的代码目前正在进行fnA中的102个分配(一个用于std :: vector,100个用于推回整数,一个用于拟合B向量中的向量)。这与fnB中的计数相同。

为提高代码速度,您可以做的唯一(少数)事情是:

  1. 如果您事先知道它的大小(这是您的代码的最大(隐藏)成本:分配),请调整向量的大小,然后使用operator []
  2. 而不是追加
  3. 使用move而不是复制(避免复制)
  4. 如果您对自己编写移动代码没有信心,可以使用指针和unique_ptr而不是普通对象(例如std::vector<std::unique_ptr<std::vector<int>>>)。
  5. 界面可能如下所示:

    struct B
    {
        std::vector<std::unique_ptr<std::vector<int>>> array;
        void append(std::vector<int> * v) { array.push_back(v); }
    
        std::vector<int> & operator[] (const size_t index) { return *array[index]; }
    };
    
    struct A
    {
        B & b;
        void fnA() {
            // One allocation here
            std::vector<int> * v = new std::vector<int>;
            v->reserve(100);  // Another allocation here
            for(size_t i = 0; i < 100; v++) {
                (*v)[i] = rand();
            }
            b.append(v); // Final allocation here => it's optimal
        }
    
        void exampleUse() { int i = b[0][2]; }
        [...]
    };