每当我需要将动态分配的对象添加到向量中时,我一直按照以下方式执行:
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
但问题是新的方式冗长乏味,我看到没有人这样做。 (至少不在我身边......)
我应该采用新的方式吗?
或者,我可以坚持旧方式吗?
或者,有更好的方法吗?
答案 0 :(得分:11)
您的新方式是更多例外安全,但您有理由不在其他地方看到它。
vector
指针只拥有指针,它不表示指向对象的所有权。您实际上是将所有权释放给不想“拥有”所有权的对象。
大多数人会使用vector
shared_ptr
来正确表达所有权或使用boost::ptr_vector
之类的内容。这两者中的任何一个都意味着您不必显式地delete
存储指针的对象,这些对象容易出错并且在程序的其他位置可能异常“危险”。
修改:您仍需要非常小心地插入ptr_vector
。不幸的是,push_back
采用原始指针提供了强有力的保证,这意味着插入成功或(有效地)没有发生,因此传入的对象既不被接管也不被破坏。采用智能指针的版本定义为在调用强保证版本之前调用.release()
,这实际上意味着它可能泄漏。
使用vector
shared_ptr
和make_shared
更容易正确使用。
答案 1 :(得分: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抛出的构造函数(我们知道它不会,因为T是指针类型)。听起来合理,但合理!保证。
所以,除非在这个问题上有一个有益的答案:
这段代码取决于实施没有做太“富有想象力”的事情。如果做不到这一点,你的问题解决方案可能会被模糊起来:
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
,那么您可以相应地修改模板。但是,在不同的情况下传递很多不同的参数列表会很困难。
答案 2 :(得分:3)
执行此操作的首选方法是使用智能指针容器,例如,std::vector<std::shared_ptr<Foo> >
或std::vector<std::unique_ptr<Foo> >
(shared_ptr
也可以在Boost和C ++ TR1中找到; std::unique_ptr
实际上仅限于C ++ 0x)。
另一种选择是使用拥有动态对象的容器,例如Boost指针容器库提供的容器。
答案 3 :(得分:0)
您的计划对内存短缺的恢复程度如何?如果你真的关心这一点,你必须准备好new
投掷。如果你不打算处理,我不会担心跳过push_back
箍。
在一般情况下,如果内存不足,该程序已经存在可能无法解决的问题,除非它专门设计为在受限的占用空间(嵌入式系统)中永久运行 - 在这种情况下,您必须关心所有这些案例。
如果这适用于您,您可以在您面前进行冗长的代码审核和重新测试。我的猜测是你可以在这里跟随你的团队的练习。
正如其他人所指出的那样,使用vector
存储原始指针有其自身的问题,并且此站点上有大量材料,而在其他答案中则指示您使用更安全的模式。