I’m refreshing my C++ knowledge after not having used it in anger for a number of years. In writing some code to implement some data structure for practice, I wanted to make sure that my code was exception safe. So I’ve tried to use std::auto_ptrs in what I think is an appropriate way. Simplifying somewhat, this is what I have:
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));
...
}
So I’m wrapping the function that would put the pointer into the container, vector::push_back, and relying on the by-value auto_ptr argument to
ensure that the Node* is deleted if the vector resize fails.
Is this an idiomatic use of auto_ptr to save a bit of boilerplate in my
Tree::insert? Any improvements you can suggest? Otherwise I’d have to have
something like:
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();
which kind of clutters up what would have been a single line of code if I wasn’t
worrying about exception safety and a memory leak.
(Actually I was wondering if I could post my whole code sample (about 300 lines) and ask people to critique it for idiomatic C++ usage in general, but I’m not sure whether that kind of question is appropriate on stackoverflow.)
It is not idiomatic to write your own container: it is rather exceptional, and for the most part useful only for learning how to write containers. At any rate, it is most certainly not idiomatic to use
std::autp_ptrwith standard containers. In fact, it’s wrong, because copies ofstd::auto_ptraren’t equivalent: only oneauto_ptrowns a pointee at any given time.As for idiomatic use of
std::auto_ptr, you should always name yourauto_ptron construction:Because the C++ standard allows arguments to evaluate in any arbitrary order, the call to
danger()is unsafe. In the call totrp()indanger(), the compiler may allocate the integer, then create theauto_ptr, and finally callwtv(). Or, the compiler may allocate a new integer, callwtv(), and finally create theauto_ptr. Ifwtv()throws an exception thendanger()may or may not leak.In the case of
safe(), however, because theauto_ptris constructed a-priori, RAII guarantees it will clean up properly whether or notwtv()throws an exception.