Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When is the compiler allowed to optimize auto+brace style initialization?

Suppose you have a class called Product, defined like this:

class Product
   {
   public:
      Product(const char *name, int i);
      Product(Product &&rhs);
      Product(const Product &rhs);
      ~Product();
   private:
      const char *m_name;
      int m_i;
   };

and you initialize a variable like this:

auto p = Product{"abc",123};

I thought that the standard dictated that a compiler must logically do the following:

  • construct a temporary Product
  • move-construct p (using the temporary Product)

But that the compiler was allowed to optimize this so that p is directly constructed.

I verified this (Visual Studio 2013) and indeed, the compiler optimizes this, even if we have our own custom (non-default) move-constructor. This is fine.

However, if I explicitly delete the copy- and move-constructor, like this:

class Product
   {
   public:
      Product(const char *name, int i);
      Product(Product &&rhs) = delete;
      Product(const Product &rhs) = delete;
      ~Product();
   private:
      const char *m_name;
      int m_i;
   };

The auto+brace initialization still compiles. I though the compiler had to prevent this because there is no copy- or move- allowed.

Strange enough, if I make the deleted copy- and move-constructor private, like this:

class Product
   {
   public:
      Product(const char *name, int i);
      ~Product();
   private:
      Product(Product &&rhs) = delete;
      Product(const Product &rhs) = delete;
      const char *m_name;
      int m_i;
   };

Then the auto+brace initialization doesn't compiler anymore.

error C2248: 'Product::Product' : cannot access private member declared in class 'Product'

Is this expected behavior? Is this a bug in Visual Studio 2013 (Update 3)?

Note: I tried compiling this on ideone and there it indeed refuses to compile the initialization when the copy- and move-constructors are deleted (and public). So I think this is a Visual Studio bug.

like image 367
Patrick Avatar asked Jun 26 '15 16:06

Patrick


1 Answers

the standard is very clear as you mentioned before, indicating that this is a bug in the cl-compiler. You never can be sure, though if one compiler is saying something and all others disagree, I expect that this would be one of the many non-standard-compliant implementations of the MSVC compiler.

The interpretation of clang version 3.7 (svn-build):

t.cpp:19:7:{19:11-19:30}: error: call to deleted constructor of 'Product'
      [Semantic Issue]
        auto p = Product{"abc", 123};
              ^   ~~~~~~~~~~~~~~~~~~~
t.cpp:8:2: note: 'Product' has been explicitly marked deleted here
      [Semantic Issue]
        Product(Product &&rhs) = delete;
         ^
1 error generated.
make: *** [t.o] Error 1

The interpretation of gcc 4.8:

t.cpp: In function ‘int main()’:
t.cpp:19:29: error: use of deleted function ‘Product::Product(Product&&)’
  auto p = Product{"abc", 123};
                             ^
t.cpp:8:2: error: declared here
  Product(Product &&rhs) = delete;
  ^
make: *** [build/gcc/t.o] Error 1

Keep also in mind that the Explicitly Defaulted and Deleted Functions are new since MSVC 2013 and the implementation of it is not yet complete. Like it does not yet understand =default for move constructors.

My guess would be that MSVC 2013 does not check for the move constructor or simply falls back to the copy constructor.

It might be interesting to check MSVC 2015, since it appears to have a (more) complete implementation of these constructions.

JVApen

like image 83
JVApen Avatar answered Oct 29 '22 16:10

JVApen