如何从类返回大向量而不复制数据

How to return large vector from class without copying data

本文关键字:复制 数据 向量 返回      更新时间:2023-10-16

我正在编写一个程序,其中一个类具有一个大std::vector的数据成员(在100k - 1M项的顺序上)。其他类需要能够访问这个向量。目前,我有一个返回vector的标准访问函数,但我认为这里返回的是vector的副本。我认为直接返回一个迭代器或指向第一个元素的指针会更节省内存和时间。然而,如果我这样做,那么如何使用这个指针通过vector运行,并知道何时停止(即向量结束的地方)?

我的代码是这样的:

class MyClass
{
    private:
        std::vector<MyObj> objects_;
        //...
    public:
        std::vector<MyObj> getObjects() { return objects_; }
        //...
}

当我想运行(模拟)连接向量时,这个问题以另一种形式出现。如果我有vector (MyClass),我希望能够遍历所有包含的object_向量。我从这个答案中知道boost::join做了我想要的,但我想我需要返回副本才能工作。我可以返回一个指向向量的指针,并且仍然保留对它和其他连续迭代的能力吗?

为了避免性能损失,返回引用。

// Non-const version
std::vector<MyObj>& getObjects() { return objects_;}
// const version
std::vector<MyObj> const& getObjects() const { return objects_; }

但是,在进行更改之前,必须考虑公开对成员变量的引用的缺点。它使你的课程不那么灵活。如果将objects_更改为另一种类型的容器更有意义,而不影响该类的所有用户,则无法轻松地将其更改为其他类型的容器。

通过委托给vector数据成员,使您的类充当集合。当然,您可能需要重新访问使用MyClass的代码但是,注释掉getObjects()之后,编译器会告诉你大部分的修改可能

那一行。
MyClass heapsOfThem;
// ...
// just delete the `getObjects()` *and use MyClass::iterator*
// instead of std::vector::iterator.
// for(std::vector<MyObj>::iterator it=
//    heapsOfThem.getObjects().begin()...
// )
for(MyClass::iterator it=heapsOfThem.begin()...)

委托代码在下面一行——一旦你修复了你的调用代码,你可以改变你的想法,使用什么类型(vector, list, set)作为你的对象的内部容器,而不改变调用代码。

class MyClass
{
    private:
        std::vector<MyObj> objects_;
        //...
    public:

        const size_t size() const {
          return objects_,size();
        }
        MyObj& operator[](size_t i) {
          return objects_[i];
        }
        const MyObj& operator[](size_t i) const {
          return objects_[i];
        }
        using iterator = std::vector<MyObj>::iterator;
        iterator begin() {
          return objects_.begin();
        }
        iterator end() {
          return objects_.end();
        }
        // TODO const iterators following the same pattern
        // *if you aren't good enough with the above*
        // uncomment it and let it return a *reference* 
        // std::vector<MyObj>& getObjects() { return objects_; }
        //...
}

您可以重构类,使其具有返回数组元素和数组大小的公共方法,因此所有其他类都可以获取值,而无需复制整个向量。

public:
    unsigned int getMyObjArraySize();
    MyObj getMyObjElementAt(unsigned int index);

使用这种方法,只有一个vector实例,但任何协作都可以通过两个公开size的公共方法和通过索引访问值的访问器来完成。

这种方法适合使用for循环而不是迭代器。

MyClass myClass;
// ...
MyObj myObj;
for(unsigned int i; i < myClass.getMyObjArraySize(); i++) {
    myObj = myClass.getMyObjElementAt(i);
    // do stuff
}

返回指向vector的指针是没有问题的。

std::vector<MyObj>* getObjects() { return &objects_; }

然后当你想对它进行迭代时,只需解引用:

std::vector<MyObj>* objectsPtr = getObjects();
for (auto& it : *objectsPtr)
{
   ...
}

但是,请确保在从vector对象中读取数据的同时没有写入vector对象,因为这样会使迭代器失效。