17

While testing the VS2015 C++ compiler I stumbled upon a strange bug with the default keyword. If I do:

struct Dummy
{
    Dummy() = default;
    Dummy(const Dummy &) = delete;
};  

int main()
{
    const Dummy& ref = Dummy();
    return 0;
}

I get

error C2280: 'Dummy::Dummy(const Dummy &)': attempting to reference a deleted function
note: see declaration of 'Dummy::Dummy'

But if I use an empty constructor

struct Dummy
{
    Dummy() {}
    Dummy(const Dummy &) = delete;
};

int main()
{
    const Dummy& ref = Dummy();
    return 0;
}

The code compiles. Running the first example with g++ or clang produces no error.

Why would using the default constructor with VS2015 try to use the copy constructor where it doesn't in g++ or clang?

vladon
  • 8,158
  • 2
  • 47
  • 91
pdondziak
  • 253
  • 1
  • 7

1 Answers1

11

It is definitely a bug in VS 2015.

In C++11, assigning temporary to const reference must not call copy constructor, but VS 2015 does.

You can check it with

#include <iostream>

struct Dummy
{
    Dummy() = default;
    Dummy(const Dummy &) { std::cout << "copy ctor" << std::endl; }
    void test() const { std::cout << "test" << std::endl; }
};  

int main()
{
    const Dummy& ref = Dummy();
    ref.test();
    return 0;
}

compiled on VS 2013, 2015, gcc and clang. Only VS (any version) calls copy constructor, if class constructor defined as = default.

I think VS compiiler still in 2015 erroneously uses old C++03 standard rules for this (8.5.3.5 of C++03):

If the initializer expression is an rvalue, with T2 a class type, and "cv1 T1" is reference-compatible with "cv2 T2," the reference is bound in one of the following ways (the choice is implementation-defined):

-- The reference is bound to the object represented by the rvalue (see 3.10) or to a sub-object within that object.

-- A temporary of type "cv1 T2" [sic] is created, and a constructor is called to copy the entire rvalue object into the temporary. The reference is bound to the temporary or to a sub-object within the temporary.

The constructor that would be used to make the copy shall be callable whether or not the copy is actually done.

VS developers chose second way. They corrected this for empty user-defined constructor ({}), but forgot to do this for defaulted (= default) constructors.

PS. Bug on MS Connect (please vote)

vladon
  • 8,158
  • 2
  • 47
  • 91