1

I have been trying to debug this for a while now without any luck. I was hoping to get some help here. Apologies if my question isn't relevant or something, I'm new.

So basically what I have is:

#include <iostream>

template<typename T> class Node {
    using NodePtr = std::shared_ptr<Node<T>>;
private:
    Node() {}
    T value{};
    NodePtr parent;
    NodePtr child;
public:
    Node(const T& value) : value{ value } {}
    Node(const T& value, NodePtr child) : Node(value)
    {
        this->child = child;
        if (child != NULL)
        {
            //problem here?  
            child->parent = NodePtr(this);
       
             /*The equivalent in C# works perfectly fine:*/
            
                /*this.child = child;
                if(child != null) {
                    child.parent = this;
                }*/
            

        }
    }

    const T& Value()    const { return value; }
    T& ValueRef()       const { return value; }
    NodePtr Parent()     const { return parent; }
    NodePtr Child()     const { return child; }
};
template<typename T> std::ostream& operator<<(std::ostream& stream, const Node<T>& node) {
    stream << "{" << node.Value() << "}";
    return stream;
}
int main()
{
    Node<int> n{ 5, std::make_shared<Node<int>>(3) };
    std::cout << n;
}

I can implement this easily without using smart pointers, but I'm trying to learn them so there's that.

The assertion that is failing: "is_block_type_valid(header->_block_use)"

Image of the assertion error

Any help would be appreciated, thank you.

Weston McNamara
  • 386
  • 5
  • 13
somenpc323
  • 13
  • 3
  • 1
    When you see assertions like that, the actual error is underneath the source file. In this case the error/failed assertion is "is_block_type_valid(header->_block_use)", which may help you, if you google around for that in specific. – Weston McNamara Oct 20 '21 at 19:23
  • Possibly related: https://stackoverflow.com/questions/1102123/debug-assertion-failed-expression-block-type-is-valid – Weston McNamara Oct 20 '21 at 19:23
  • It looks like you're getting a double free by having two unrelated shared pointers to a `Node`. You will need to use [`std::enable_shared_from_this`](https://en.cppreference.com/w/cpp/memory/enable_shared_from_this). – Fred Larson Oct 20 '21 at 19:50
  • 1
    See also [Using shared_from_this in templated classes](https://stackoverflow.com/questions/17853212/using-shared-from-this-in-templated-classes). – Fred Larson Oct 20 '21 at 19:55
  • I'm so sorry @FredLarson, I've been trying to implement that without luck. Could you write an example showing how to? – somenpc323 Oct 20 '21 at 20:17
  • I haven't succeeded either. I believe it's a couple of things. First, the `n` instance in main also has to be a `shared_ptr`. You can't use `shared_from_this` on something that doesn't have any shared pointers pointing to it, and you mustn't have a `shared_ptr` to something on the stack. Second, by doing the link in a constructor, you run into a problem because the `this` doesn't have `shared_ptr` pointing to it until after the constructor completes. It's a chicken-and-egg sort of problem. – Fred Larson Oct 20 '21 at 20:25

1 Answers1

0

There are a few problems. First, if you want to get a shared_ptr from this, you have to inherit from std::enable_shared_from_this:

template<typename T> class Node : std::enable_shared_from_this<Node<T>> {
    // ...

The main problem is that there is a shared_ptr referencing a shared_ptr (the parent to the child, vice-versa). However, shared_ptr are only reference-counted. Take a look at the program below:

#include <iostream>
#include <memory>
struct A;

struct B{
    std::shared_ptr<A> sp;
    ~B(){ std::cout << "B destroyed\n"; }
};
struct A{
    std::shared_ptr<B> sp;
    ~A(){ std::cout << "A destroyed\n"; }
};

int main(){
    std::shared_ptr<B> b{};
    std::shared_ptr<A> a {b->sp};
    b = a->sp;
}

The output is blank! Here is a link to the above program.

To fix, do two additional things: one, change child->parent = NodePtr(this); to the following:

child->parent = this->weak_from_this();

Also, change the type of parent to std::weak_ptr<Node<T>>.

std::weak_ptr is used with problems like this. It doesn't influence the reference count of the std::shared_ptr For more information, go here.

P.S. the error about the is_block_type was caused by shared_ptr, probably because you tried to get a shared_ptr from a raw ptr. Read more about std::shared_ptr here.

Captain Hatteras
  • 490
  • 3
  • 11