lundi 26 octobre 2015

Copy constructor called from derived class

Can someone explain the output here? createTreap() works fine, and r is not nullptr, but createTreapPair() leaves r == nullptr after treapPair.first.display(); treapPair.second.display();. Why? What is the difference between the two? What's going on here?

#include <iostream>
#include <memory>

class BinaryTree {
public:
    class Node {
        int value;
        std::shared_ptr<Node> left = nullptr, right = nullptr, parent = nullptr;
        friend class BinaryTree;  friend class Treap;
    public:
        Node (int v) : value(v) {}
        virtual ~Node() = default;
        Node (const Node&);
    };
    BinaryTree() : root(nullptr) {}
    BinaryTree (const BinaryTree& other) : root(std::shared_ptr<Node>(new Node(*other.root))) {std::cout << "BinaryTree copy constructor called.\n";}
    void setRoot (const std::shared_ptr<Node>& node) {root = node;}
protected:
    std::shared_ptr<Node> root;
};

BinaryTree::Node::Node (const Node& other) : value(other.value) {
    std::cout << "Node copy constructor called, value = " << value << '\n';
    if (other.left) left = std::shared_ptr<Node>(new Node(*other.left));
    if (other.right) right = std::shared_ptr<Node>(new Node(*other.right));
}

class Treap : public BinaryTree {
public:
    class Node : public BinaryTree::Node {
        int priority;
        friend class Treap;
    public:
        Node (int value) : BinaryTree::Node(value), priority(std::rand() % 100) {}
        Node (const Node& other) : BinaryTree::Node(other), priority(other.priority) {}  // Treap::Node copy constructor.
    };
    void display() const {
        std::shared_ptr<Node> r = std::dynamic_pointer_cast<Node>(root);  // Casting from BinaryTree::Node to Treap::Node.
        std::cout << "r = " <<  r << '\n';
        if (root) std::cout << "Root exists and has value " << root->value << ".\n";
    }
};

Treap createTreap() {
    std::cout << "\n\ncreateTreap() called.\n";
    Treap treap;
    std::shared_ptr<Treap::Node> r = std::make_shared<Treap::Node>(4);
    treap.setRoot(r);
    return treap;
}

std::pair<Treap, Treap> createTreapPair() {
    std::cout << "\n\ncreateTreapPair() called.\n";
    Treap treap1, treap2;
    std::shared_ptr<Treap::Node> r = std::make_shared<Treap::Node>(11);
    treap1.setRoot(r);
    treap2.setRoot(r);
    return std::make_pair(treap1, treap2);
}

int main() {
    const Treap treap = createTreap();
    treap.display();  // Works fine, r != nullptr.

    const std::pair<Treap, Treap> treapPair = createTreapPair();
    treapPair.first.display();  // r is nullptr!
    treapPair.second.display();  // r is nullptr!

    std::cin.get();
}

How to fix the above code so that r does not turn to nullptr after treapPair.first.display(); treapPair.second.display();? r is of type std::make_shared<Treap::Node> in both createTreap() and createTreapPair(), so why does r = std::dynamic_pointer_cast<Node>(root); turn r to nullptr in Treap::display()? after createTreapPair()?

Aucun commentaire:

Enregistrer un commentaire