C++矢量参考

use*_*173 13 c++ vector

我对C++如何管理向量中的对象感到困惑.说我做以下事情:

vector<MyClass> myVector;
myVector.push_back(a);
myVector.push_back(b);
MyClass & c = myVector[1];
myVector.erase(myVector.begin());
Run Code Online (Sandbox Code Playgroud)

参考c是否仍然有效(或者更好,是否保证有效)?如果没有,我是否必须始终从参考文件中复制以确保安全?

pae*_*bal 12

与Java或C#引用(更像是C++引用而不是C++引用)不同,C++中的引用与指针一样"哑",这意味着如果获得对象的引用,然后将该对象移动到内存中,则引用不再有效.

参考c是否仍然有效(或者更好,是否保证有效)?

在您描述的情况下,当向量内容发生更改(删除项目,调整向量大小等)时,不保证标准向量不会将其包含的对象保留在内存中的相同位置.

这将使迭代器和对所包含对象的指针/引用无效.

如果没有,我是否必须始终从参考文件中复制以确保安全?

有多种方法可以继续"指向"正确的对象,所有这些方式都意味着一个间接层.

完整/有价值的副本

最简单的是制作MyClass的完整副本:

vector<MyClass> x ;
x.push_back(a) ;
x.push_back(b) ;
MyClass c = x[1] ;    // c is a full copy of b, not a reference to b
x.erase(x.begin()) ;
Run Code Online (Sandbox Code Playgroud)

使用正确的容器

第二个最简单的方法是使用std::list专门为元素插入和删除而设计的a ,它不会更改包含的对象,也不会使指针,引用或迭代器无效:

list<MyClass> x ;
x.push_back(a) ;
x.push_back(b) ;
list<MyClass> it = x.begin() ;
++it ;
MyClass & c = *it ;
x.erase(x.begin()) ;
Run Code Online (Sandbox Code Playgroud)

使用指针(不安全)

另一种方法是制作一个std::vector<MyClass *>包含指针MyClass而不是MyClass对象的指针.然后,您将能够保持指向对象或对指向对象的引用,具有略微不同的表示法(因为额外的间接):

vector<MyClass *> x;
x.push_back(a);     // a being a MyClass *
x.push_back(b);     // b being a MyClass *
MyClass * c = x[1]; // c points to the same object as b
x.erase(x.begin()); // note that a will still need separate deallocation
Run Code Online (Sandbox Code Playgroud)

这是不安全的,因为没有明确的(就编译器而言)对象a和b的所有者,这意味着没有明确的代码负责在不再需要它们时解除分配它们(这就是内存泄漏的发生方式)在C和C++中)

因此,如果您使用此方法,请确保代码封装良好,并尽可能小以避免维护意外.

使用智能指针(更安全)

更好的是使用智能指针.例如,使用C++ 11(或boost)shared_ptr:

vector< shared_ptr<MyClass> > x;
x.push_back(a);               // a being a shared_ptr<MyClass>
x.push_back(b);               // b being a shared_ptr<MyClass>
shared_ptr<MyClass> c = x[1]; // c points to the same object as b
x.erase(x.begin());           // No deallocation problem
Run Code Online (Sandbox Code Playgroud)

现在,如果您使用shared_ptr并且一无所知weak_ptr,那么您就有问题,所以您应该缩小这个差距.

使用智能指针2(更安全)

另一个解决方案是使用C++ 11 unique_ptr,它是尖头对象的独占所有者.因此,如果您想要指针或对指针对象的引用,则必须使用原始指针:

vector< unique_ptr<MyClass> > x;
x.push_back(a);               // a being a unique_ptr<MyClass>
x.push_back(b);               // b being a unique_ptr<MyClass>
MyClass * c = x[1].get();     // c points to the same object as b
x.erase(x.begin());           // No deallocation problem
Run Code Online (Sandbox Code Playgroud)

请注意,向量是对象的唯一所有者,与上面的情况不同smart_ptr.

结论

您使用C++编写代码,这意味着您必须为您的问题选择正确的方法.

但首先,您需要确保了解指针添加的间接级别,指针的作用以及C++引用的作用(以及它们不是C#/ Java引用的原因).


Gre*_*ill 10

来自参考vector:

[5]当重新分配内存时,向量的迭代器无效.此外,在向量中间插入或删除元素会使指向插入或删除点后面的元素的所有迭代器无效.因此,如果使用reserve()预分配尽可能多的内存,并且所有插入和删除都在向量的末尾,则可以防止向量的迭代器失效.

因此,您的迭代器无效,并且在之后erase不得使用.

  • 问题是关于引用,而不是迭代器,但事实证明两者的答案基本相同. (2认同)

Goz*_*Goz 3

参考 c 仍然有效(或者更好的是,它保证有效)吗?

不,它现在处于未定义状态。

如果没有,我是否必须始终复制参考资料以确保安全?

如果在您检索它和使用它之间它有可能被删除或移动(等),那么是的,您确实需要制作副本。