0

Below is MyStruct class implementation which has default and copy constructors.

struct MyStruct {
    MyStruct(const string& name) {
        cout << "Basic constructor called" << endl;
        name_ = name;
    }
    MyStruct(const MyStruct& S) {
        cout << "Copy constructor called" << endl;
        name_ = S.name_;
    }
    string name_;
}

Creating an object in the following way: MyStruct S = MyStruct("Hello"); calls a constructor with "Hello" argument. I suspect my compiler (gcc version 7.5.0) does the optimisation by avoiding to create a temporary MyStruct("Hello") object.

However, the compiler does not optimize the analogous case for assignment operators:

MyStruct& operator=(const string& name) { // First assignment operator
    name_ = name;
    return *this;
}
MyStruct& operator=(const MyStruct& S) { // Second assignment operator
    name_ = S.name_;
    return *this;
}

Reassigning S to another struct:

MyStruct S = MyStruct("Hello"); // initial construction
S = MyStruct("world"); // reassignment

calls a constructor for the second time to construct the temporary MyStruct("world") object. After that, the second assignment operator is called.

Question:

  • is there a way to modify the code such that the call to the first assignment operator with an argument "world" would be called?

  • Is the first optimisation part of the modern C++ standard (i.e. will work with all compilers), or only works with specific compilers?

mercury0114
  • 1,341
  • 2
  • 15
  • 29
  • 1
    if you want to call `MyStruct& operator=(const string& name)`, then you need to assign the string directly to `S` like `S = "world";` – NathanOliver Jul 29 '20 at 18:53
  • 1
    As for the first optimization, see: https://stackoverflow.com/questions/12953127/what-are-copy-elision-and-return-value-optimization – NathanOliver Jul 29 '20 at 18:53
  • A compiler can't do that with assignment. Constructors taking arguments and assignment operators are user defined functions. And those can do... anything. A compiler can't prove that calling `operator=(const string&)` has the same behavior as calling `MyStruct(const string&)` and then `operator=(const MyStruct&)`. It can't make behavior altering optimizations. – StoryTeller - Unslander Monica Jul 29 '20 at 18:56
  • "Can modern C++ compilers optimise the assignment operator for temporary variables?" - Why don't you simply compile your code with a modern compiler with optimizations enabled and inspect the generated assembly? That would answer your question definitively. – Jesper Juhl Jul 29 '20 at 19:40
  • "MyStruct(const string& name) { cout << "Default constructor called" << endl;" - No. You are lying. That's not a default constructor. – Jesper Juhl Jul 29 '20 at 19:43
  • @StoryTeller-UnslanderMonica But why does it work for the constructor then? Why does a compiler, in this case, deduce that `MyStruct temp(string); MyStruct(temp)` is identical to `MyStruct(string)` (which might not be identical for an arbitrary constructor definition) and executes the latter? – mercury0114 Jul 29 '20 at 20:05
  • 1
    @mercury - It wasn't possible in the early days of C++. But... with constructors you don't have an *existing* object getting modified (that may have invariants). It's just storage that needs initialization. In that case, the change in observable behavior was deemed more reasonable, and thus allowed by the standard. – StoryTeller - Unslander Monica Jul 29 '20 at 20:16

1 Answers1

1

is there a way to modify the code such that the call to the first assignment operator with an argument "world" would be called?

Sure:

S = "world";

I suspect my compiler (gcc version 7.5.0) does the optimisation by avoiding to create a temporary

Is the first optimisation part of the modern C++ standard

There is no temporary since C++17 and as such the copy constructor is guaranteed to not be called.

Prior to C++17, there is a temporary object, and compilers were merely allowed to not call the copy constructor (and thus optimise the temporary away). This optimisation was implemented by all major compilers.

eerorika
  • 232,697
  • 12
  • 197
  • 326