C ++: after code failure

#include <iostream>
using namespace std;

class B
{
public:
    B() { cout << "Base B()" << endl; }
    ~B() { cout << "Base ~B()" << endl; }
private:
    int x;
};

class D : public B
{
public:
    D() { cout << "Derived D()" << endl; }
    virtual ~D() { cout << "Derived ~D()" << endl; }
};

int
main ( void )
{
    B* b = new D;
    delete b;
}


---- output----------
Base B()
Derived D()
Base ~B()
*** glibc detected *** ./a.out: free(): invalid pointer: 0x0930500c ***
======= Backtrace: =========
/lib/tls/i686/cmov/libc.so.6[0xb7d41604]
/lib/tls/i686/cmov/libc.so.6(cfree+0x96)[0xb7d435b6]
/usr/lib/libstdc++.so.6(_ZdlPv+0x21)[0xb7f24231]
./a.out[0x8048948]
/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe5)[0xb7ce8775]
./a.out[0x80487c1]
Aborted

If I remove the private member "int x" from the base class, it works fine

+3
source share
8 answers

What you do is UB, but for the particular compiler you use, the behavior can be described as follows. To simplify the ASCII graphics below by changing the example, adding a member yto Dand changing main.

#include <iostream>
using namespace std;

class B
{
public:
    B() { cout << "Base B()" << endl; }
    ~B() { cout << "Base ~B()" << endl; }
private:
    int x;
};

class D : public B
{
public:
    D() { cout << "Derived D()" << endl; }
    virtual ~D() { cout << "Derived ~D()" << endl; }
private:
    int y; // added.
};

int
main ( void )
{
    D* d = new D; // modified.
    B* b = d;
    delete b;
}

In the compiler used, the virtual table, if any, is placed at the beginning of the memory block. In the compiler, you use the memory layout for this:

+--------+
| vtable | <--- d points here, at the start of the memory block.
+--------+
| x      | <--- b points here, in the middle of the memory block.
+--------+
| y      |
+--------+

delete b free b, .

, , - .

+2

B .

+12

class B , delete class D, class B, class B - undefined. class B destructor virtual, .

+6

boost:: shared_ptr: templated constructors , D.

#include <boost/shared_ptr.hpp>

int
main ( void )
{
    boost::shared_ptr<B> b( new D );
}

.

, D, D destructor virtual.

+2

, , :

int
main ( void )
{
    D* as_d = new D;
    B *as_b = as_d;
    // you can use the object via either as_b or as_d but
    // you must delete it via as_d
    delete as_d;
}

, , .

, , , B.

+1

, (( ), ctor .

.

0

, VPTR. , B 4 .

. VPTR . , , VPTR. , D - 8 , 4 - VPTR, 4 x.

, D -a B? , , . D B-, , , REAL D, , B. , 4 . , B- > x, .

, , . undefined. .

0

, , , , "". , , "" D .

, D :

  Object D
+-----------+
| B subobj. |
+-----------+
| D members |
+-----------+

B , B, D . D 0, B - sizeof(int) (4 ), "", , , .

So, after uninstallation B, but until the end of the application, perhaps some of the compiler’s addition of code during the breakdown crashes due to your unreasoned deletion B(reusing this part of the memory, for example, or something like that).

Since your code is very short, you can check the behavior of your gdb code at the assembly level between deletion Band termination of the code.

0
source

Source: https://habr.com/ru/post/1732144/


All Articles