在多年没有生气之后,我正在刷新我的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/

10-10 13:17