1

I wrote two programs to understand the concept of copying objects. First one:

#include<bits/stdc++.h>
using namespace std;

class myInt
{
    int x;
public:
    myInt()
    {
        cout<< "default constructor is called" << endl;
    }
    myInt(int x)
    {
        cout<< "constructor is called with initializer" << endl;
        this->x = x;
    }
    ~myInt()
    {
        cout<< "destructor is called" << endl;
    }
};

myInt func(myInt ob)
{
    return ob;
}

int main()
{
    myInt ob1(2);
    func(ob1);
}

Output:

constructor is called with initializer
destructor is called
destructor is called
destructor is called

Here destructor was called 3 times which means 3 objects were created. One for object 'ob1', one for the 'ob' inside func() and another one while returning 'ob' from func(). My second code:

#include<bits/stdc++.h>
using namespace std;

class myInt
{
    int x;
public:
    myInt()
    {
        cout<< "default constructor is called" << endl;
    }
    myInt(int x)
    {
        cout<< "constructor is called with initializer" << endl;
        this->x = x;
    }
    ~myInt()
    {
        cout<< "destructor is called" << endl;
    }
};

myInt func(myInt ob)
{
    return ob;
}

int main()
{
    myInt ob1(2);
    myInt ob2 = func(ob1);
}

Output:

constructor is called with initializer
destructor is called
destructor is called
destructor is called

Here also 3 objects were created as the first one. But shouldn't there be one more destructor call for 'ob2' as I store the returning object from func() in it? Why the number of destructor call is same in both cases?

  • 4
    Return value optimization: `ob2` is not really created. See also: [copy elision](https://en.cppreference.com/w/cpp/language/copy_elision). – freakish Mar 25 '21 at 07:36
  • 2
    Take a look of this [question](https://stackoverflow.com/questions/12953127/). – karastojko Mar 25 '21 at 07:37

1 Answers1

3

As pointed out in the comments, due to copy elision, creating temporaries may be omitted when they are only used to initialize another object. Compile your code with -fno-elide-constructors to turn it off and you will read destructor is called four times. Here is a demo.

However, in c++17 things are different. It guarantees that copies are elided in certain situations (prvalue used as the initializer of an object with the same type). There, it is no longer considered an optimization (i.e. -fno-elide-constructors has no effect here). See this nice article or the proposal for details. The following example (stolen from the linked article) compiles fine with c++17 as we are guaranteed that no copy-/move constructors are called:

struct Foo {
  Foo() { std::cout << "Constructed" << std::endl; }
  Foo(const Foo &) = delete;
  Foo(const Foo &&) = delete;
  ~Foo() { std::cout << "Destructed" << std::endl; }
};

Foo f() {
  return Foo();
}

int main() {
  Foo foo = f();
}
StefanKssmr
  • 1,196
  • 9
  • 16