Copy-constructor of multilevel classes

Consider this piece of code:

#include <vector> #include <iostream> using namespace std; class Base { char _type; public: Base(char type): _type(type) {} ~Base() { cout << "Base destructor: " << _type << endl; } }; class uncopyable { protected: uncopyable() {} ~uncopyable() {} private: uncopyable( const uncopyable& ); const uncopyable& operator=( const uncopyable& ); }; class Child : public Base, private uncopyable { int j; public: Child(): Base('c') {} ~Child() { cout << "Child destructor" << endl; } }; int main() { vector<Base> v; Base b('b'); Child c; v.push_back(b); v.push_back(c); return 0; } 

The output on my system is:

 Base destructor: b Child destructor Base destructor: c Base destructor: b Base destructor: b Base destructor: c 

My questions:

  • Why is the Base destructor (with type b) called three times instead of two (we have more than two instances of object b)?

  • What happens when we copy an object of type Child , given that the copy-constructor of one of its parents is private. Is this behavior undefined?

  • I expected to get a compile-time error whenever I try to copy an object of type Child . I thought that the default constructor instance created by default would try to call a private instance copy of the Uncopyable class and cause a compilation error. Why doesn't it give compilation errors?

The reason this code is designed this way is because the Child class is huge.

The desired behavior throws out child data whenever the client tries to copy the Child object (calling the Child destructor without calling the Base destructor).

This piece of code achieves this, but I assume that it leads to undefined behavior and has a memory leak (it never calls the Child destructor for the copied instance).

+6
source share
3 answers

Here is what happens in your code:

 int main() { vector<Base> v; // 1 Base b('b'); // 2 Child c; // 3 v.push_back(b); // 4 v.push_back(c); // 5 return 0; } // 6 
  • line 1: the constructed vector v

  • line 2: base b is built (calling the base constructor)

  • line 3: constructed child c (call the constructor Child and constructor Base)

  • line 4: v has maximum bandwidth and needs to be changed.
    Memory is allocated for 1 Base by v element.
    Base b is copied to v [0] (calling the base copy constructor).

  • line 5: v again has the maximum capacity and needs to be changed.
    Memory is allocated for two Base by v elements.
    Old v [0] is copied to new v [0] (the calling constructor of the base copy).
    Old v [0] is deleted (calling the base destructor ("base destructor: b")).
    Child c is copied to v [1] (calling the base copy constructor).

  • line 6: c, b and v end.
    Child c is deleted (calling Child destructor ("Tree structure detector"), then the base destructor ("Base destructor: c").
    Base b is deleted (calling the base destructor ("base destructor: b")).
    Databases v [0], v [1] are deleted (Base destructor is called twice ("Base destructor: b", "Base destructor: c")).

No memory leak - for each constructor, the corresponding destructor is called in the specified sequence.

Also, you seem very confused about copy constructors. Child c is passed push_back as Base & - which then calls the base copy constructor as expected. Since the Base implicit copy constructor is not virtual or overridden, having Child from uncopyable does not change anything.

Note that a vector<Base> cannot store an object of type Child; he knows that he allocates enough memory for the Base. What happens when you assign a Child instance to the database is called slicing, which, although often unintentionally and misunderstood, seems to really be what you want in the scenario you describe.

+9
source

I expected to get a compile-time error whenever I try to copy an object of type Child.

You are not copying the Child object. When you put Child c in vector<Base> , only Base copied. This is basically the same as doing b = c; . If you copy / assign Child , you will receive an error message.

 Child d = c; // compile error 

The default copy constructor will invoke copy constructors of any base class and member objects, and a bitwise copy for primitives and pointers.

+3
source

EDIT: The answer is incorrect. Currently editing the best answer.

Why is the Base destructor (with type b) called three times instead of two (we have more than two copies of object b)?

Most likely, the vector creates a copy of b . Vectors do this often.

What happens when we copy an object of type Child, given that the copy-constructor of one of its parents is private. Is this behavior undefined?

Not. The copy constructor C will invoke the copy constructor of the base classes. Therefore, if copy constructors of the base class are private, it will not compile.

I need to get a compile-time error whenever I try to copy an object of type Child while allowing copying of objects of the base class. What is the best way to do this?

Declare a private copy constructor for the Child as follows:

 private: Child(const Child& a) { throw "cannot make a copy"; } 

The desired behavior throws out the child data whenever the client tries to copy the child object (calling the Child destructor without calling the base destructor).

Not sure what you mean. Copy constructor means creating a new object. You cannot perform operations on an (old) object.

0
source

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


All Articles