Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Derived from two Bases - Delete vector **strange** problem [duplicate]

Tags:

c++

I am hours trying to figurate out where is the problem, but it seems so strange.

I rewrote my problem in an easier way to understand.

When it gets to the line where it says delete, the debbug makes a breakpoint.

Ps. Intresting to note that, if we take int b1 and move it to Base2 it works.

Base1:

#pragma once
class Base1
{
public:
    Base1();
    ~Base1();
    int b1;
};

Base2.h:

#pragma once
#include <iostream>
#include <vector>
class Derived;
class Base2
{
public:
    Base2();
    ~Base2();
    std::vector <std::vector <Base2*>> vec;
    void doSomething(Derived& d);
};

Base2.cpp:

#include "Base2.h"
#include "Derived.h"


Base2::Base2()
{
    //the numbers 1 and 5 does not really metter
    vec.resize(1);
    vec[0].resize(5);
}


Base2::~Base2()
{
}

void Base2::doSomething(Derived& d)
{
    vec[0][d.b1] = new Derived();
    delete vec[0][d.b1];
}

Derived:

#pragma once
#include "Base1.h"
#include "Base2.h"
class Derived : public Base1, public Base2
{
public:
    Derived();
    ~Derived();
};

main:

#include <iostream>
#include "Derived.h"

int main()
{
    Derived d;
    d.b1 = 1;
    d.doSomething(d);
}
like image 727
Isaac Michaan Avatar asked Dec 27 '18 14:12

Isaac Michaan


1 Answers

Base2 lacks a virtual destructor.

Deleting a derived object via a pointer to it's base, if that base doesn't have a virtual destructor, leads to undefined behavior.


Usually this kind of UB only leads to missing destructor calls (and thus memory/resource leaks), but in this case, since multiple inheritance is involved, the situation is different.

When you convert a pointer returned by new Derived() to Base2 *, the numerical value of the pointer changes (due to multiple inheritance).

After delete calls ~Base2(), it subsequently passes the pointer to a memory deallocation function.
The deallocation function expects the same address that was returned by new, which is the address of an entire Derived instance. Instead it gets an address of Base2 subobject, which is different (again, due to multiple inheritance).

This is no different from any other "attept to delete a pointer that wasn't returned by new" situation, and usually results in a crash.

If Base2 had a virtual destructor, the pointer would be adjusted to point to the entire instance of Derived before deallocation.

like image 77
HolyBlackCat Avatar answered Nov 15 '22 03:11

HolyBlackCat