c++classassignment-operatorcopy-assignmentexplicit-constructor

C++ copy assignment operator behaviour


I used the code below to test the behaviour of copy assignment operator:

#include <iostream>
using namespace std;

int group_number = 10; // Global

class Player {
public:
  explicit Player(const int &g): group(g)
  {
  }

  Player& operator=(const Player& rhs)
  {
      cout << "Copy assignment operator called " << endl;
      return *this;
  }

  void set_stamina(int i) {stamina = i; }
  int  get_stamina()      {return stamina; }
  const int &get_group()  const { return group; }

protected:
  const int &group;

private:
  int stamina;
}; // End of Player class

class Round {
public:
  Round(const Player &p)
  {
    main_player = &p;
  }

  const Player &get_main_player() const
  {
    return *main_player;
  }

protected:
  const Player *main_player;
}; // End of Round class

// Test code
int main()
{
  Player p1(group_number);
  Round r(p1);
  p1.set_stamina(100);

  // Add player2 in the same group as p1
  Player p2(group_number);
  p2 = r.get_main_player();
  cout << "This is p1's stamina: "    << p1.get_stamina()
       << ", and p1's group number: " << p1.get_group() << endl;;
  cout << "This is p2's stamina: "    << p2.get_stamina()
       << ", and p2's group number: " << p2.get_group() << endl;;

  return 0;
}

I expected both p1 and p2 have the same value of stamina. But the output shows that p2's stamina is different from p1's

Copy assignment operator called
This is p1's stamina: 100, and p1's group number: 10
This is p2's stamina: 241098768, and p2's group number: 10

Why the copy assignment operator not copying the value of p1's stamina to p2?


Solution

  • You have not copied the data member stamina inside the copy assignment operator. So just add stamina = rhs.stamina; inside the copy assignment operator and you'll get your expected output. So the modified definition of operator= looks like:

    Player& operator=(const Player& rhs)
      {
          cout << "Copy assignment operator called " << endl;
          stamina = rhs.stamina; //ADDED THIS 
          return *this;
      }
    

    Also, note that in your original code snippet, since the data member stamina is not initilized and so it has indeterminate value. Using this uninitialized variable(which you do when you wrote p2.get_stamina();) is undefined behavior.

    Undefined behavior means anything1 can happen including but not limited to the program giving your expected output. But never rely(or make conclusions based) on the output of a program that has undefined behavior.

    So the output that you're seeing is a result of undefined behavior. And as i said don't rely on the output of a program that has UB.

    So the first step to make the program correct would be to remove UB. Then and only then you can start reasoning about the output of the program.

    To solve this more serious problem just use in-class initilaizer for data member stamina.

    class Player {
        //other members here
    private:
      int stamina = 0; //USE IN-CLASS INITIALIZER
    };
    

    1For a more technically accurate definition of undefined behavior see this where it is mentioned that: there are no restrictions on the behavior of the program.