An instance of a copy of a class that has a user class member

I read thinking in C ++, chapter 14: "Functions that don't automatically inherit"

class GameBoard { public: GameBoard() { cout << "GameBoard()\n"; } GameBoard(const GameBoard&) { cout << "GameBoard(const GameBoard&)\n"; } GameBoard& operator=(const GameBoard&) { cout << "GameBoard::operator=()\n"; return *this; } ~GameBoard() { cout << "~GameBoard()\n"; } }; class Game { GameBoard gb; // Composition public: // Default GameBoard constructor called: Game() { cout << "Game()\n"; } // You must explicitly call the GameBoard // copy-constructor or the default constructor // is automatically called instead: Game(const Game& g) : gb(g.gb) { //Game(const Game& g) { cout << "Game(const Game&)\n"; } Game(int) { cout << "Game(int)\n"; } Game& operator=(const Game& g) { // You must explicitly call the GameBoard // assignment operator or no assignment at // all happens for gb! gb = g.gb; cout << "Game::operator=()\n"; return *this; } class Other {}; // Nested class // Automatic type conversion: operator Other() const { cout << "Game::operator Other()\n"; return Other(); } ~Game() { cout << "~Game()\n"; } }; 

In the above code, I am confused by the copy constructor and the assignment constructor of the Game class:

  // You must explicitly call the GameBoard // copy-constructor or the default constructor // is automatically called instead: Game(const Game& g) : gb(g.gb) { //Game(const Game& g) { cout << "Game(const Game&)\n"; } Game& operator=(const Game& g) { // You must explicitly call the GameBoard // assignment operator or no assignment at // all happens for gb! gb = g.gb; cout << "Game::operator=()\n"; return *this; } 

The author gives a comment: " You must explicitly call the GameBoard copy-constructor constructor, otherwise the default constructor will automatically be called: " Why, if I do not call the explicit GameBoard copy-constructor expression, will the default constructor be called?

And for the assignment constructor , if I do not explicitly call the GameBoard assignment GameBoard , then no assignment happens. Why?

+4
source share
3 answers

Why, if I do not explicitly refer to the GameBoard constructor, then will the default constructor be called?

If you did not write any explicit copy constructor for Game , then the compiler would generate this copy of gb for you. On the other hand, at the moment you explicitly define your own copy constructor, the compiler thinks: "Well, this guy really knows what he is doing, so give him full control ."

With full control, you are also responsible for clearly indicating all the actions you want to take when creating a copy. If you do not specify any actions, then the compiler must accept that the default mechanism for building objects is accepted. The default mechanism for building objects is to call the default constructor.

Since you seem to know what you are doing, the compiler will not make any assumptions about the correct build procedure for your member variables. You need complete control, now you have: forgot something? You get the default construct.

if I do not explicitly call the GameBoard assignment operator, then no assignment occurs. Why?

The answer is pretty similar. By explicitly defining your own operator = , you tell the compiler that you want full control over how objects are assigned. The compiler will not try to get in the way by making assumptions that may be incorrect. Instead, he will simply put aside and give you all the power to make decisions.

On the other hand, suppose the compiler silently generated the assignment gb = g.gb , but for some (hopefully good) reason you did not want this assignment to be executed: how would you tell the compiler not to execute it if the default behavior was to generate such an instruction?

Also, if it’s not really required, it’s good programming practice that allows the compiler to implicitly create a copy / move constructor, destructor and copy / move assignment operator for your class: for more information see this article by R. Martinho Fernandes on the so-called Rule zero .

Hope this helped clarify.

+4
source

These comments really do not make sense to me.

If you simplify the code like this:

 #include <iostream> using namespace std; class GameBoard { public: GameBoard() { cout << "GameBoard()\n"; } GameBoard(const GameBoard&) { cout << "GameBoard(const GameBoard&)\n"; } GameBoard& operator=(const GameBoard&) { cout << "GameBoard::operator=()\n"; return *this; } ~GameBoard() { cout << "~GameBoard()\n"; } }; class Game { GameBoard gb; // Composition }; int main() { cout << "Default Constructing Game object\n"; Game g; cout << "\nCopy constructing Game object\n"; Game h = g; // uses copy ctor cout << "\nDefault constructing another Game object\n"; Game i; cout << "\nAssigning a Game object\n"; i = g; // uses assignment operator. return 0; } 

You will (or should, in any case) get the output as follows:

 Default Constructing Game object GameBoard() Copy constructing Game object GameBoard(const GameBoard&) Default constructing another Game object GameBoard() Assigning a Game object GameBoard::operator=() ~GameBoard() ~GameBoard() ~GameBoard() 

Perhaps he says that what happens by default will not happen by default when defining your own constructor / assignment operator. If so, this is true (and perhaps we are confused for the same reason: because it seems to be unusually obvious).

0
source

When setting up the copy constructor and assignment operator, you need to handle all of your member variables.

If you do not code the copy constructor and / or assignment operator, by default the compiler generates by default. Keep in mind that the default values ​​perform minor assignments and copies. Both simply go through each member variable and use their assignment operators or copy constructors.

 // NOTE don't you strdup or free in c++ (see new, delete and the string class) // this is for BAD example only class Stuff { public: char * thing; Stuff( void ) : thing(0) {} ~Stuff() { if( thing ) free thing; }; void copyThing( char * other ) { thing = strdup(other); } } class Other { public: Stuff myStuff; } void BadExample() { Other oa; oa.copyThing( "Junk" ); Other ob; ob = oa; // will work but oa and ob myStuff.thing will point to the same address // and you will attempt to free it twice during deconstruction } class BetterStuff { public: char * thing; BetterStuff( void ) : thing(0) {} ~BetterStuff() { if( thing ) free thing; }; void copyThing( char * other ) { thing = strdup(other); } BetterStuff & operator = ( const BetterStuff & rhs ) { if( rhs.thing ) thing = strdup( rhs.thing ); } } class BetterOther { public: BetterStuff myStuff; } void Example() { BetterOther oa; oa.copyThing( "Junk" ); BetterOther ob; ob = oa; // now ob has a private copy of the string and can free it. } 
0
source

All Articles