6

每当我需要将动态分配的对象添加到向量中时,我一直在这样做:

class Foo { ... };

vector<Foo*> v;

v.push_back(new Foo);

// do stuff with Foo in v

// delete all Foo in v

它刚刚奏效,许多其他人似乎也在做同样的事情。

今天学习了vector::push_back可以抛出异常。这意味着上面的代码不是异常安全的。:-( 所以我想出了一个解决方案:

class Foo { ... };

vector<Foo*> v;
auto_ptr<Foo> p(new Foo);

v.push_back(p.get());
p.release();

// do stuff with Foo in v

// delete all Foo in v

但问题是新方法冗长乏味,而且我看到没有人这样做。(至少不在我身边……)

我应该走新路吗?
或者,我可以坚持旧的方式吗?
或者,有没有更好的方法呢?

4

4 回答 4

11

您的新方法安全,但有一个原因是您在其他任何地方都看不到它。

A vectorof pointers 仅拥有指针,它不表示指向对象的所有权。您正在有效地将所有权释放给不“想要”所有权的对象。

大多数人会使用vectorofshared_ptr来正确表达所有权或使用类似boost::ptr_vector. 这些中的任何一个都意味着您不必显式地显示delete要存储其指针的对象,这些对象在程序的其他点上容易出错并且可能出现异常“危险”。

编辑:您仍然必须非常小心插入ptr_vector. 不幸的是,push_back采用原始指针提供了强有力的保证,这意味着插入成功或(有效地)没有任何事情发生,因此传入的对象既不会被接管也不会被销毁。按值获取智能指针的版本被定义为.release()在调用强保证版本之前调用,这实际上意味着它可以泄漏。

将 a vectorofshared_ptr与 with 一起使用make_shared更容易正确使用。

于 2010-11-15T14:43:19.860 回答
11

如果您只关心此操作的异常安全性:

v.reserve(v.size()+1);  // reserve can throw, but that doesn't matter
v.push_back(new Foo);   // new can throw, that doesn't matter either.

向量负责释放其内容所指向的对象的问题是另一回事,我相信你会得到很多关于这个的建议;-)

编辑:嗯,我打算引用标准,但实际上我找不到必要的保证。我正在寻找的是push_back不会抛出,除非(a)它必须重新分配(我们知道它不会因为容量),或者(b)T throws 的构造函数(我们知道它不会' t 因为 T 是指针类型)。听起来合理,但合理!=保证。

所以,除非在这个问题上有一个有益的答案:

除了重新分配或构造失败之外,是否允许 std::vector::push_back 抛出?

这段代码取决于实现没有做任何太“富有想象力”的事情。如果做不到这一点,您可以对问题的解决方案进行模板化:

template <typename T, typename Container>
void push_back_new(Container &c) {
    auto_ptr<T> p(new T);
    c.push_back(p.get());
    p.release();
}

然后使用并不太乏味:

struct Bar : Foo { };

vector<Foo*> v;
push_back_new<Foo>(v);
push_back_new<Bar>(v);

如果它真的是一个工厂函数而不是new那么你可以相应地修改模板。但是,在不同情况下传递许多不同的参数列表会很困难。

于 2010-11-15T14:46:46.650 回答
3

执行此操作的首选方法是使用智能指针容器,例如,astd::vector<std::shared_ptr<Foo> >或 a std::vector<std::unique_ptr<Foo> >shared_ptr也可以在 Boost 和 C++ TR1 中找到;std::unique_ptr实际上仅限于 C++0x)。

另一种选择是使用拥有动态对象的容器,例如 Boost Pointer Containers 库提供的那些容器。

于 2010-11-15T14:43:46.057 回答
0

您的程序对内存短缺的适应能力如何?如果你真的关心这个,你也必须做好new投掷的准备。如果你不打算处理这个问题,我不会担心跳过push_back篮球。

在一般情况下,如果内存不足,则程序可能已经存在无法克服的问题,除非它专门设计为在受限空间(嵌入式系统)中永久运行 - 在这种情况下,您必须关心所有这些情况。

如果这适用于您,您可能会面临漫长的代码审查和重新测试周期。不过,我的猜测是,您可以在这里遵循团队的做法。

正如其他人所指出的那样,使用vector存储原始指针有其自身的问题,并且该站点和其他答案中有大量材料可以指导您使用更安全的模式。

于 2010-11-15T14:42:51.780 回答