在多年没有生气之后,我正在刷新我的C++知识。在编写一些代码以实现一些数据结构以供实践时,我想确保我的代码是异常安全的。因此,我尝试以我认为合适的方式使用std::auto_ptr
。有点简化,这就是我所拥有的:
class Tree
{
public:
~Tree() { /* delete all Node*s in the tree */ }
void insert(const string& to_insert);
...
private:
struct Node {
...
vector<Node*> m_children;
};
Node* m_root;
};
template<T>
void push_back(vector<T*>& v, auto_ptr<T> x)
{
v.push_back(x.get());
x.release();
}
void Tree::insert(const string& to_insert)
{
Node* n = ...; // find where to insert the new node
...
push_back(n->m_children, auto_ptr<Node>(new Node(to_insert));
...
}
因此,我包装了将指针放入容器的函数
vector::push_back
,并依靠按值auto_ptr
参数来如果
Node*
调整大小失败,请确保删除vector
。这是
auto_ptr
的惯用用法,用于在我的系统中保存一些样板Tree::insert
?您可以提出任何改进建议吗?否则我将不得不就像是:
Node* n = ...; // find where to insert the new node
auto_ptr<Node> new_node(new Node(to_insert));
n->m_children.push_back(new_node.get());
new_node.release();
如果我不是这样的话,那种困惑会变成一行代码
担心异常安全和内存泄漏。
(实际上,我想知道是否可以发布我的整个代码示例(大约300行),并要求人们对C++的惯用用法进行一般性的批判,但我不确定对于stackoverflow这种问题是否合适。)
最佳答案
编写自己的容器并不是惯用的:这是异常(exception),并且在大多数情况下仅对学习如何编写容器有用。无论如何,将std::autp_ptr
与标准容器一起使用绝对不是习惯。实际上,这是错误的,因为std::auto_ptr
的副本并不等效:在任何给定时间只有一个auto_ptr
拥有一个pointe。
至于std::auto_ptr
的惯用用法,应始终在构造时命名auto_ptr
:
int wtv() { /* ... */ }
void trp(std::auto_ptr<int> p, int i) { /* ... */ }
void safe() {
std::auto_ptr<int> p(new int(12));
trp(p, wtv());
}
void danger() {
trp(std::auto_ptr<int>(new int(12)), wtv());
}
因为C++标准允许参数以任意顺序求值,所以对
danger()
的调用是不安全的。在对trp()
中的danger()
的调用中,编译器可以分配整数,然后创建auto_ptr
,最后调用wtv()
。或者,编译器可以分配一个新的整数,调用wtv()
,最后创建auto_ptr
。如果wtv()
引发异常,则danger()
可能会泄漏也可能不会泄漏。但是,对于
safe()
,因为auto_ptr
是先验构造的,所以RAII保证无论wtv()
是否引发异常,它都将正确清理。关于c++ - 惯用auto_ptr将所有权转移到容器,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/2862195/