я бы просто изменить само дерево, было бы легче иметь дело с ним, то:
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;
};
Будучи объектно-ориентированным, каждый узел теперь отвечает за память он обрабатывает. Кроме того, использование интерфейса std::auto_ptr
в интерфейсе дает понять, что он требует права собственности.
Обратите внимание, что он предназначен для глубокого копирования, любого другого подхода, требующего boost::shared_ptr
или его эквивалента. И да std::auto_ptr
оставляет вам дело с копированием самостоятельно, без магии.
Эта конструкция намного чище, чем использование простой C-struct
, при этом каждый может манипулировать ресурсами. Вы по-прежнему иметь полный доступ к базовым данным через аксессор ... но они заботятся, чтобы не вызвать неопределенное поведение ...
Конечно, вы можете разбить его вниз:
Node& node = ...
delete node.left(); // haha
Но если C++ может защитить от непреднамеренных проблем, он оставляет дверь открытой для злого кода.
Почему это происходит, когда он проверяет правый узел, он ничего не находит, но когда он проверяет левый узел, он что-то находит? – neuromancer
Потому что 'root' просто указывает на память мусора. Другие результаты могут включать только левые, оба, ни один, ни крушение. – Potatoswatter