Pat*_*zyk 8 c++ pointers vector std
最近我认识到我不应该使用指针向量.我想知道 - 为什么我不能?
例如,如果我有一个类foo,可以这样做:
vector <foo*> v;
v.push_back(new foo());
Run Code Online (Sandbox Code Playgroud)
我已经看到有些人投票这种做法,为什么呢?
Ste*_*fan 11
使用原始指针的向量并不是必要的坏样式,只要你记住指针没有所有权语义.当你开始使用new和时delete,通常意味着你做错了什么.
特别是,你应该使用new或delete在现代C++代码中使用的唯一情况是构造unique_ptr,或者使用自定义删除器构建shared_ptr.
例如,假设我们有实现的双向的类Graph,一个Graph含有一定量Vertexes.
class Vertex
{
public:
Vertex();
// raw pointer. No ownership
std::vector<Vertex *> edges;
}
class Graph
{
public:
Graph() {};
void addNode()
{
vertexes.push_back(new Vertex); // in C++14: prefer std::make_unique<>
}
// not shown: our Graph class implements a method to traverse over it's nodes
private:
// unique_ptr. Explicit ownership
std::vector<std::unique_ptr<Vertex>> vertexes;
}
void connect(Vertex *a, Vertex *b)
{
a->edges.push_back(b);
b->edges.push_back(a);
}
Run Code Online (Sandbox Code Playgroud)
请注意我是如何Vertex在Vertex该类中使用raw*的向量的?我可以这样做,因为Vertexes它指向的生命周期由类管理Graph.Vertex只需查看代码,我的类的所有权就是明确的.
一个不同的答案建议使用shared_ptr.我个人不喜欢这种方法,因为共享指针通常很难推断出对象的生命周期.在这个特定的例子中,共享指针根本不起作用,因为它之间的循环引用Vertexes.
Rud*_*lis 10
在容器中存储普通指针可能会导致内存泄漏和悬空指针.将指针存储在容器中并不会定义指针的任何类型的所有权.因此容器不知道解构和复制操作的语义.当从容器中移除元素时,容器不知道如何正确地销毁它们,当执行复制操作时,不知道所有权的语义.当然,你总是可以自己处理这些事情,但是仍然有可能出现人为错误.
使用智能指针将所有权和破坏语义留给他们.
另外要提到的是容器分为非侵入式和侵入式容器 - 它们存储实际提供的对象而不是副本,因此它实际上归结为一组指针.非侵入式指针有一些优点,因此您无法概括容器中的指针是应该始终避免的,仍然在大多数情况下建议使用.
因为向量的析构函数不会调用delete指针,所以很容易意外泄漏内存.向量的析构函数调用向量中所有元素的析构函数,但原始指针没有析构函数.
但是,您可以使用智能指针向量来确保销毁向量将释放其中的对象. vector<unique_ptr<foo>>可以在C++ 11中使用,在C++ 98中使用TR1可以使用vector<tr1::shared_ptr<foo>>(虽然shared_ptr与原始指针相比具有轻微的开销或unique_ptr).
Boost还有一个指针容器库,其中特殊的delete-on-destruction行为内置于容器本身,因此您不需要智能指针.
其中一个问题是异常安全.
例如,假设在某处抛出异常:在这种情况下,std::vector调用析构函数.但这个析构函数调用并不会删除原所属指针存储在矢量.因此,这些指针管理的资源被泄露(这些资源可能都是内存资源,因此您有内存泄漏,但它们也可能是非内存资源,例如套接字,OpenGL纹理等).
相反,如果你有一个智能指针向量(例如std::vector<std::unique_ptr<Foo>>),那么如果调用向量的析构函数,则向量中的每个指向项(由智能指针安全拥有)都会被正确删除,并调用它的析构函数.因此,与每个项目相关联的资源(向量中"巧妙地"指向)被正确释放.
注意观察原始指针的向量很好(假设观察到的项的寿命超过向量的寿命).问题在于原始 拥有指针.
| 归档时间: |
|
| 查看次数: |
10070 次 |
| 最近记录: |