Me basta con cambiar el árbol en sí, sería más fácil tratar con él, entonces:
struct Node
{
Node(data_type data): mLeft(), mRight(), mData(data) {}
Node(const Node& rhs): mLeft(), mRight(), mData(rhs.mData)
{
if (rhs.mLeft.get()) mLeft.reset(new Node(*rhs.mLeft));
if (rhs.right.get()) mRight.reset(new Node(*rhs.mRight));
}
Node& operator=(Node rhs)
{
this->swap(rhs);
return *this;
}
~Node() { }
void swap(Node& rhs)
{
using std::swap;
swap(mLeft, rhs.mLeft);
swap(mRight, rhs.mRight);
swap(mData, rhs.mData);
}
Node* left() const { return mLeft.get(); }
void left(std::auto_ptr<Node> node) { mLeft= node; }
Node* right() const { return mRight.get(); }
void right(std::auto_ptr<Node> node) { mRight = node; }
data_type& data() { return mData; }
const data_type& data() const { return mData; }
private:
std::auto_ptr<Node> mLeft;
std::auto_ptr<Node> mRight;
data_type mData;
};
Al estar orientada a objetos, cada nodo es ahora responsable de la memoria que maneja. Además, el uso std::auto_ptrde la interfaz deja claro que se necesita la propiedad.
Tenga en cuenta que ha sido adaptado para deep-copia, cualquier otro enfoque que requiere boost::shared_ptro equivalente. Y sí std::auto_ptrte deja hacer frente a la copia por sí mismo, no hay magia allí.
Este diseño es mucho más limpio que el uso de una llanura C-structcon todo el mundo ser capaz de manipular los recursos. Todavía tiene acceso completo a los datos subyacentes a través del descriptor de acceso ... pero tenga cuidado de no invocar un comportamiento indefinido ...
Por supuesto, todavía puede bloquearse hacia abajo:
Node& node = ...
delete node.left(); // haha
Pero si C ++ puede proteger contra los problemas no deseados, deja la puerta abierta al código maligno.