-1

I understand that f(ClassA str) pass by value and return by value, so

f(str) call copy constructor 2 times;

f(f(str)) call copy constructor 4 times;

str1 = f(f(str)) call copy constructor 5 times.

But the result is 2,3,3.

Moreover, if i change the definition of f into ClassA f(ClassA &str), there is a error initial value of reference to non-const must be an lvalue. How could this error come?

#include<iostream>

using namespace std;

class ClassA
{
    int a, b;
public:
    ClassA()
    {
        a = 10;
        b = 20;
    }
    ClassA(const ClassA &obj)
    {
        a = obj.a; b = obj.b;
        cout << "copy constructor called" << endl;
    }
};

ClassA f(ClassA str)
{
    return str;
}

int main(){
       ClassA str;
       ClassA str1;
       str1 = f(f(str));

}
user6703592
  • 1,004
  • 1
  • 12
  • 27
  • *How many times will copy constructor be called...* -- It depends on your compiler, compiler version, optimization settings, etc. There is no concrete answer. – PaulMcKenzie Sep 15 '19 at 18:52

1 Answers1

0

UPD: ClassA explicitly declare only copy constructor. So, ClassA has defaulted copy assignment operator

If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy assignment operator is defined as deleted; otherwise, it is defined as defaulted

And hasn't defaulted move constructor

If the definition of a class X does not explicitly declare a move constructor, a non-explicit one will be implicitly declared as defaulted if and only if (8.1) — X does not have a user-declared copy constructor, (8.2) — X does not have a user-declared copy assignment operator, (8.3) — X does not have a user-declared move assignment operator, and (8.4) — X does not have a user-declared destructor.

Instead, move constructor ClassA use copy constructor

Note: When the move constructor is not implicitly declared or explicitly supplied, expressions that otherwise would have invoked the move constructor may instead invoke a copy constructor. — end note ]

Copy elision happen in f(f(str))

in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (...) with the same type (ignoring cv-qualification) as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function call’s return object

Summaries: f(str) - by default : copy constructor + move constructor; in this case : copy constructor + copy constructor

f(f(str)) - by default : copy constructor + copy elision + move constructor + move constructor; in this case : copy constructor + copy elision + copy constructor + copy constructor

str1 = f(f(str)) - in this case : copy constructor + copy elision + copy constructor + copy constructor + copy assignment operator (not copy constructor What's the difference between assignment operator and copy constructor?)

It's possible to have another result, for example, if use flag "-fno-elide-constructors" in gcc. It disables copy elision Disabling g++'s return-value optimisation

f(str) return rvalue object. In ClassA f(ClassA &str) you take lvalue references. Interesting that ClassA f(const ClassA& str) doesn't give error Const reference and lvalue

np_king
  • 33
  • 6
  • 1
    Is this correct, where you can pinpoint a certain number (3 in your case)? The number of times a copy constructor is invoked depends on the compiler and various optimization settings. – PaulMcKenzie Sep 15 '19 at 18:54