1
class Test {
  int *arr{nullptr};

public:
  Test() : arr(new int[5000]{1, 2, 3, 4}) {
    cout << "default constructor" << endl;
  }

  Test(const Test &t) {
    cout << "copy constructor" << endl;
    if (arr == nullptr)
      arr = new int[5000];
    memcpy(arr, t.arr, 5000 * sizeof(int));
  }

  Test(Test &&t) : arr(t.arr) {
    cout << "move constructor" << endl;
    t.arr = nullptr;
  }

  ~Test() {
    cout << "destructor" << endl;
    delete[] arr;
  }

  int *Arr() const { return arr; } 
};

int main()
{
    Test t(Test{});
    // Test t((Test()));
}

In main function, if I changed “Test t(Test{})” to "Test t(std::move(Test{}))" or "Test t(std::forward(Test{}))", it will call once default constructor and once move constructor. But, "Test t(Test{})" itself only call once default constructor, that is so wierd to my understanding. any one can help? very thanks for you!

Gorden Xu
  • 51
  • 2
  • 1
    [Copy elision](https://en.cppreference.com/w/cpp/language/copy_elision). – songyuanyao Sep 01 '20 at 12:45
  • According to my understanding, Test{} as argument of ctor, it should be treated as rvalue, which mean should call move ctor consequently. But it is not, very confusing to me – Gorden Xu Sep 01 '20 at 12:48
  • Your understanding is incorrect. C++ has copy elision, and C++17 has guaranteed copy elision (prior to C++17 it was optional by compiler implementation). That's why side-effects, such as the output in your example, may not occur and is discouraged from putting any side-effects (especially necessary side-effects!) in constructors. – Eljay Sep 01 '20 at 12:50
  • As songyuanyao explained, this is copy elision. C++ standard allows to optimize calls like this to avoid extra copy (or move). In gcc you can use `-fno-elide-constructors` flag to disable this optimization and force move construction along the way (provided that you are using C++14 or older, C++17 mandates copy elision). [See it online](https://wandbox.org/permlink/1pSr834WyYgyXzit) – Yksisarvinen Sep 01 '20 at 12:51

0 Answers0