1

I am the following structure. I minimized to the shortest possible way to reproduce the error:

I have two level of derived class. I don't have any compilation error. The error is at the runtime:

Unhandled exception at 0x00007FFF1021CF19 in base.exe: Microsoft C++ exception: std::__non_rtti_object at memory location 0x00000022B9BDF458.

Is there any suggection?

#include <iostream>
#include <vector>
#include <memory>

class Base {
public:
    int a;
    Base(int _a) : a(_a) {};
    virtual void print() = 0;
};

class derivedA : public Base
{
public:
    derivedA(int _a) : Base(_a) {};
    void print() { std::cout << "dA" << std::endl; }
};

class derivedB : public derivedA
{
public:
    derivedB(int _a) : derivedA(_a) {};
    void print() { std::cout << "dB" << std::endl; }
};

void construct(std::vector<derivedA*>& da_vec) {
    da_vec.push_back(std::unique_ptr<derivedA>(new derivedB(4)).get());
}

void func(derivedA& da)
{
    derivedB& db = dynamic_cast<derivedB&>(da);
    db.print();
}

int main()
{
    std::vector<derivedA*> da_vec;
    construct(da_vec);
    for (auto& da : da_vec)
        func(*da);
}
wohlstad
  • 12,661
  • 10
  • 26
  • 39
H'H
  • 1,638
  • 1
  • 15
  • 39
  • 9
    Why are you doing `da_vec.push_back(std::unique_ptr(new derivedB(4)).get());`? That pointer you just added gets deleted when the temporary unique_ptr is destroyed. – NathanOliver May 25 '23 at 13:42
  • My main problem is within func function. when I have a reference to the derivedA and I want to get the reference to a derivedB – H'H May 25 '23 at 13:44
  • 4
    No it isn't. Because of the first problem you do not have a reference to derivedA, the object has been deleted before you get to that point. – john May 25 '23 at 13:45
  • 2
    Your problems start before that. The pointer you add in construct doesn't point to anything. The thing it pointed to was deleted as soon as the temporary `unique_ptr` you created was destroyed at the end of the full expression it was created in. – NathanOliver May 25 '23 at 13:46
  • I took your code, replaced `da_vec.push_back(std::unique_ptr(new derivedB(4)).get());` with `da_vec.push_back(new derivedB(4));` and it ran successfully. I guess you think `std::unqiue_ptr` works differently to how it actually works. – john May 25 '23 at 13:52
  • [What is a debugger and how can it help me diagnose problems?](https://stackoverflow.com/questions/25385173/what-is-a-debugger-and-how-can-it-help-me-diagnose-problems) – Jesper Juhl May 25 '23 at 13:53
  • 2
    You should be using `std::vector>` and `da_vec.emplace_back(new derivedB(4));` or `da_vec.push_back(std::make_unique(4));`. Of course you still need to add a virtual destructor to `derivedA` or `Base`... – fabian May 25 '23 at 13:53

1 Answers1

5
  • When you push_back the derivedB base class pointer, you store a dangling pointer.
    da_vec.push_back(std::unique_ptr<derivedA>(new derivedB(4)).get());
    
    The unique_ptr<derivedA> is destroyed at the end of the expression, so the pointer you got from .get() is "dangling", which means that it should not be dereferenced. The object it pointed at is gone.

To solve that, I suggest that you instead store std::unique_ptr<derivedA> in your vector. You also do not need to cast to derivedB& before calling the overridden print method. That's what polymorphism solves for you automatically.

Example:

void construct(std::vector<std::unique_ptr<derivedA>>& da_vec) {
    da_vec.push_back(std::make_unique<derivedB>(4));
}

void func(derivedA& da) {
    //derivedB& db = dynamic_cast<derivedB&>(da);
    da.print();
}

int main() {
    std::vector<std::unique_ptr<derivedA>> da_vec;
    construct(da_vec);
    for (auto& da : da_vec)
        func(*da);
}

Demo

Note: I made the Base destructor virtual too which is necessary in order to destroy objects via a base class pointer in order for all the destructors to be called (from most derrived to the base).

I also marked the overridden methods with override which is not strictly necesssary, but helps when reading the code - and it will also give you a compilation error in case you think you override something, but actually isn't.

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108