1
struct X
{
  // default c
  X() 
  {
    i++;
    j = i; 
    std::cout<<"X() "<<j<<std::endl;
  } 

  // copy constructor
  X(const X&) { std::cout<<"X(const X&)"<<std::endl; } 

  // copy assignment operator
  X& operator=(const X&) 
  {
    std::cout<<"operator= "<<j<<std::endl;
  }
  // destructor
  ~X() { std::cout<<"~X() "<<j<<std::endl; } // destructor

  static int i; 
  int j;
};

int X::i = 0; 

X fa() 
{
  return X(); 
}

X& fb(X& x)
{
  return x; 
}

int main()
{
  X x1; 
  X* x2 = new X; 

  std::cout << "\n----- X x3 = fa();\n";
  X x3 = fa(); // Q1 

  std::cout << "\n----- X x4 = fb(x1);\n";
  X x4 = fb(x1); // Q2

  std::vector<X> vx; 
  vx.psh_back(x1);

  std::cout << "\n----- vx.push_back(*x2);\n";
  vx.push_back(*x2); // Q3

  return 0;
}

Running this program produces the following output,

X() 1

----- X x3 = fa();
X() 2

----- X x4 = fb(x1);
X(const X&)
X() 3
X(const X&)

----- vx.push_back(*x2);
X(const X&)
X(const X&)
~X() 0
~X() 0
~X() 0
~X() 0
~X() 2
~X() 1

Its not clear to me what is happening in Q1, Q2, Q3.

In Q1, why is the copy constructor skipped, and why is the destructor not called when the function goes out of scope?

In Q2, why is the final call to the copy constructor and not the assignment operator?

In Q3, why is the copy constructor called twice before the destructor? As the push_back causes the existing element to be copied into the next to last address shouldn't the order be copy constructor, destructor, copy constructor?

TWhite
  • 45
  • 6
  • 5
    All of these three questions are pretty much unrelated, but all of them have many duplicates, for example Q1: https://stackoverflow.com/questions/12953127/what-are-copy-elision-and-return-value-optimization. Q2: https://stackoverflow.com/questions/10595451/why-copy-constructor-is-called-here-instead-of-normal-constructor-and-overloaded Q3: https://stackoverflow.com/questions/26740523/vector-push-back-calling-copy-constructor-more-than-once – user17732522 Feb 19 '22 at 06:26
  • Thanks for those links, however the explanation for Q3 still doesn't explain why the destructor is not called? – TWhite Feb 21 '22 at 13:59
  • 1
    The vector will copy the existing element to the new allocation, then copy-construct the new element and only then destroy the old element in the old allocation, because it needs to make sure that the `push_back` can be rolled-back if the copy-constructor of the new element throws an exception. – user17732522 Feb 21 '22 at 16:47
  • thanks for the explanation. Once the second element is copy-constructed into the end of the vector, wouldn't this overwrite the previous object? Why the need for a destructor at all in this situation? – TWhite Feb 22 '22 at 13:53
  • 1
    I am not sure what you mean, after the new element has been copy-constructed in the new allocation, there are three objects: one copy of the first element in the old allocation, one copy of the first element in the new allocation and one copy of the second element in the new allocation. The old allocation isn't needed anymore after that, so it is destroyed, calling the destructor on the copy of the first element in the old allocation. – user17732522 Feb 22 '22 at 18:24
  • thanks- this really clarifies it, I had an incorrect mental model. I assumed that the vector would extend contiguously from where it assigned the first first element. But this isn't the case, instead a completely new vector with two addresses is used. – TWhite Feb 23 '22 at 13:44

0 Answers0