Home > Back-end >  Why disabling copy elision for std::atomic doesn't work using C 17?
Why disabling copy elision for std::atomic doesn't work using C 17?

Time:05-20

For std::atomic the copy constructor is deleted, and this should only compile with C 17 and higher due to copy elision:

std::atomic<int> t_int = 1; 

I expected that it does not compile using -fno-elide-constructors flag, but it still compiles:

https://godbolt.org/z/nMvG5vTrK

Why is this?

CodePudding user response:

C 17 doesn't simply say that the previously optional return value optimizations are now mandatory. The actual description of the language changed so that there is no creation of a temporary object anymore in the first place.

So, since C 17, there is no constructor call that could be elided anymore. Hence it makes sense that -fno-elide-constructors doesn't add any temporary creation. That would be against the language rules.

Before C 17 the language describes that a temporary object is created from which the variable is initialized and then adds that a compiler is allowed to elide this temporary. Therefore, whether -fno-elide-constructors is used or not, the compiler is behaving standard compliant by eliding or not eliding the temporary copy.

CodePudding user response:

I expected that it does not compile using -fno-elide-constructors flag,

The given flag has no effect on return value optimization(aka RVO) from C 17 and onwards. This is because it is not considered an optimization anymore(from C 17) but instead it is a language guarantee.

From mandatory copy elison:

Under the following circumstances, the compilers are required to omit the copy and move construction of class objects, even if the copy/move constructor and the destructor have observable side-effects. The objects are constructed directly into the storage where they would otherwise be copied/moved to. The copy/move constructors need not be present or accessible:

  • In the initialization of an object, when the initializer expression is a prvalue of the same class type (ignoring cv-qualification) as the variable type:

(emphasis mine)

This means that t_int is constructed directly from the prvalue 1. And the flag -fno-elide-constructors has no effect on RVO which is different from NRVO. And so the copy constructor being deleted has no effect in your case.

Perhaps an example might help illustrating the same,

struct Custom 
{
    public:
      Custom(int p): m_p(p)
      {
          std::cout<<"converting ctor called"<<std::endl;
      }
      Custom(const Custom&) = delete; //deleted copy ctor
    private:
      int m_p = 0;
};
int main()
{
    Custom c = 1; //works in C  17 but not in Pre-C  17
}
  • Related