0

While testing some classes I run into an interesting problem: When invoking class constructor using the equals sign notation (=) if the copy constructor is deleted an error is encountered error: copying variable of type 'Class' invokes deleted constructor. While using the parenthesis the code compiles normally.

What is going on here? Can this be a compiler bug?

Consider the following class:

class Test
{
    public:
        int Int;

    public:
        Test() = default;
        Test(Test &) = delete;
        Test(Test &&) = delete;
        Test(int i)
        {
            Int = i;
        }
};

Constructors invoked like so:

Test t1(3);  //No error
Test t2 = 3; //error: copying variable of type 'Class' invokes deleted constructor

Just to check I tried to add some checks and allow these functions and compile the code. Both constructors compiled using MSVC in the exact same way.

class Test
{
    public:
        int Int;

    public:
        Test()
        {
            Int = 0;
            cout << "Constructor";
        }
        Test(Test &t)
        {
            Int = t.Int;
            cout << "Copy Constructor";
        }
        Test(Test &&t)
        {
            Int = t.Int;
            cout << "Move Constructor";
        }
        Test(int i)
        {
            Int = i;
            cout << "Constructor from int";
        }
};
Test t1(3);  //Constructor from int
Test t2 = 3; //Constructor from int

What exactly is going on here?

Jakubek K.
  • 31
  • 3
  • 1
    This is *not* C#. Looks like C++. – itsme86 May 31 '19 at 21:54
  • 1
    Lets take a step back here... You need to work out what language you are in (as you seem confused and it will hinder your research) – TheGeneral May 31 '19 at 21:56
  • Oh I am so sorry, I put the wrong tag! I will change it ASAP – Jakubek K. May 31 '19 at 21:58
  • 1
    That's not the `=` operator; that's initialization (by copy). – melpomene May 31 '19 at 22:10
  • Great suggestion by @Chris Dodd! This is certainly very close to the answer. Though I dont quite understand in the first paragraph of explanation is stated: "The copy/move constructors need not be present or accessible, as the language rules ensure that no copy/move operation takes place, even conceptually:" but in the first paragraph under the explanation is stated: "This is an optimization: even when it takes place and the copy/move (since C++11) constructor is not called, it still must be present and accessible (as if no optimization happened at all),". I dont understand the ambiguity. – Jakubek K. May 31 '19 at 22:27
  • Note that the copy ctor is *usually* `Test(const Test &)` -- while you can define it without the const, doing so [has some subtle effects](https://stackoverflow.com/questions/11683959/can-a-copy-constructor-take-a-non-const-parameter) which are usually undesirable (particularly since the introduction of rvalue/move semantics) – Chris Dodd May 31 '19 at 22:45

1 Answers1

1

You're seeing the results of the copy elision rule.

Basically, saying T var = expr; constructs an unnamed temp from expr and then copies or moves it into var using the copy or move construtor. If the copy and move constructors are deleted, then this gives an error about the deleted constructor. But then, the compiler is required to elide that copy or move and construct var directly from expr, even if the copy or move constructor has visible side effects. Its one of those weird corner cases that arises from language design by de-facto standardization of what disparate implementations do (or did at some time in the past), plus design-by-committee and slow evolution over time while trying to keep backwards compatibility.

see here for more discussion

Chris Dodd
  • 119,907
  • 13
  • 134
  • 226