c++classpointerssegmentation-faultclass-members

C++: Private class pointer member returns undefined values


I am trying to print the level-order of a red-black tree, however, the pointers to other nodes always return any numbers after being inserted into the STL queue. What am I doing wrong here?

Here is the implementation of my node class:

// rbtree-node.h
class RBTreeNode
{
public:
  // RBTreeNode(int value, Color color) : value_(value), color_(color), left_(nullptr), right_(nullptr), parent_(nullptr) {}
  RBTreeNode(int value, Color color) : value_(value), color_(color) {}
  ~RBTreeNode()
  {
    delete left_;
    delete right_;
    delete parent_;
  }

  void setLeft(RBTreeNode *node);
  RBTreeNode *getLeft();

  void setRight(RBTreeNode *node);
  RBTreeNode *getRight();

  void setParent(RBTreeNode *node);
  RBTreeNode *getParent();

  void setValue(int value);
  int getValue();

  void setColor(Color color);
  Color getColor();

  bool hasRedChild();
  bool isParentLeftChild();

  void print();

private:
  int value_;
  RBTreeNode *left_ = nullptr;
  RBTreeNode *right_ = nullptr;
  RBTreeNode *parent_ = nullptr;
  Color color_;
};
// rbtree-node.cpp
void RBTreeNode::setLeft(RBTreeNode *node)
{
  this->left_ = node;
}

RBTreeNode *RBTreeNode::getLeft()
{
  return this->left_;
}

void RBTreeNode::setRight(RBTreeNode *node)
{
  this->right_ = node;
}

RBTreeNode *RBTreeNode::getRight()
{
  return this->right_;
}

void RBTreeNode::setParent(RBTreeNode *node)
{
  this->parent_ = node;
}

RBTreeNode *RBTreeNode::getParent()
{
  return this->parent_;
}

void RBTreeNode::setValue(int value)
{
  this->value_ = value;
}

int RBTreeNode::getValue()
{
  return this->value_;
}

void RBTreeNode::setColor(Color color)
{
  this->color_ = color;
}

Color RBTreeNode::getColor()
{
  return this->color_;
}

bool RBTreeNode::isParentLeftChild()
{
  return this->parent_ != NULL && this->parent_->left_ == this;


void RBTreeNode::print()
{
  std::cout << "Value: " << this->value_ << ", Color: " << this->color_ << ", Left: " << this->left_ << ", Right: " << this->right_ << std::endl;
}

Then I insert one node:

    // ...
    RBTreeNode node = RBTreeNode(n, BLACK);
    root_ = &node;
    return root_;
    // ...

Afterwards I try to print it here:

void RedBlackTree::printLevelOrder()
{
  // Use BFS in order to print the tree
  std::queue<RBTreeNode *> queue;
  queue.push(root_);

  while (!queue.empty())
  {
    RBTreeNode *current = queue.front();
    std::cout << "Queue: ";
    std::cout << "Value: " << current->getValue() << "(L: " << current->getLeft() << ", R: " << current->getRight() << ") "
              << std::endl;

    if (current->getLeft() != NULL)
    {
      queue.push(current->getLeft());
    }

    if (current->getRight() != NULL)
    {
      queue.push(current->getRight());
    }
    queue.pop();
  }
  std::cout << std::endl;
}

When running it, I always get a segmentation fault because the left and right node-members always return random values.

Thank you already in advance for your help!


Solution

  • One issue is that you're storing pointers to local variables within the queue:

    RBTreeNode node = RBTreeNode(n, BLACK);   // locally created value
    root_ = &node;   // pointer to local
    return root_;    // returning pointer to local.  If used outside the function, undefined behavior
    

    Basically you should design your code to hold pointers to objects that will still be alive when you access the object through that pointer.

    One suggestion would be to use dynamic allocation, i.e.

    RBTreeNode* node = new RBTreeNode(n, BLACK);
    root_ = node; 
    return root_; 
    

    Of course you now have to manage the memory correctly (proper cleanup / deallocation using delete, etc.).

    Another alternative is to use smart pointers such as std::unique_ptr that handle the clean up for you once the pointer goes out-of-scope.