Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why It is illegal to copy an object if a member of the class is a reference?

I met a quiz saying that the code in line 18 below is ill-formed because "It is ill-formed to use an implicitly defined assignment operator when one of the members that will need to be copied is a reference. "

I couldn't understand that. Why reference could not be copied? Why Line 16 is legal? Line 16 is quite similar to line 18, a copy constructor still need to do the copy, right?

1 #include <iostream>
2
3 struct A
4 {
5   A(int& var) : r(var) {}
6
7   int &r;
8 };
9
10 int main(int argc, char** argv)
11 {
12   int x = 23;
13
14   A a1(x);
15
16   A a2 = a1;
17
18   a2 = a1;
19
20   return 0;
21 }
like image 267
athos Avatar asked Jan 06 '15 05:01

athos


People also ask

Why is it necessary to pass an object by reference in a copy constructor?

It is necessary to pass object as reference and not by value because if you pass it by value its copy is constructed using the copy constructor. This means the copy constructor would call itself to make copy. This process will go on until the compiler runs out of memory.

Does reference make a copy?

The point of "pass by reference" is to not make a copy as soon as Employee constructor is called, but only when you choose to initialize one of Employee's member with the Date passed.

Can references be copied C++?

C++ gives you the choice: use the assignment operator to copy the value (copy/value semantics), or use a pointer-copy to copy a pointer (reference semantics). C++ allows you to override the assignment operator to do anything your heart desires, however the default (and most common) choice is to copy the value.

Does an object created with a copy constructor reference the same memory location that the original object references?

The copy constructor and assignment operator just do different things where references are concerned. The copy constructor initializes the reference to point to the same object that the reference points to in the instance that is being copied; the assignment operator actually copies the value of the referenced object.


3 Answers

Line 16 uses a copy constructor, line 18 uses the assignment operator operator=. Two different functions with different restrictions.

Because a reference can't be rebound, the compiler can't generate an implicit assignment operator that makes any sense. Thus it refuses to do so, and generates an error.

A copy constructor is generating the object for the first time, so it can bind that reference the same way you did in your own constructor.

like image 93
Mark Ransom Avatar answered Oct 19 '22 22:10

Mark Ransom


A class with a reference member has no default-provided copy/move assignment operators. References cannot be rebound to reference a different variable once binding is established. In short, the copy constructor is making that initial establishment, while the default assignment operator would be trying to change it after-binding.

The standard therefore calls this case out for both default copy and move assignment operators.

C++11 § 12.8p23

A defaulted copy/move assignment operator for class X is defined as deleted if X has:

  • a variant member with a non-trivial corresponding assignment operator and X is a union-like class, or
  • a non-static data member of const non-class type (or array thereof), or
  • a non-static data member of reference type, or
  • a non-static data member of class type M (or array thereof) that cannot be copied/moved because overload resolution (13.3), as applied to M’s corresponding assignment operator, results in an ambiguity or a function that is deleted or inaccessible from the defaulted assignment operator, or
  • a direct or virtual base class B that cannot be copied/moved because overload resolution (13.3), as applied to B’s corresponding assignment operator, results in an ambiguity or a function that is deleted or inaccessible from the defaulted assignment operator, or
  • for the move assignment operator, a non-static data member or direct base class with a type that does not have a move assignment operator and is not trivially copyable, or any direct or indirect virtual base class.

You can certainly write your own overload.

#include <iostream>

struct A
{
    A(int& var) : r(var) {}

    int &r;

    A& operator=(const A& obj)
    {
        r = obj.r; // value copied, reference-binding remains the same
        return *this;
    }
};

int main(int argc, char** argv)
{

    int x = 42;
    int y = 43;

    A a1(x);
    A a2(y);

    A a3 = a1; // legal. default copy-ctor invoked
    a3 = a2;   // legal. user-defined copy-assignment invoked

    std::cout << x << ',' << y << '\n';

    return 0;
}

Output

43,43

But this will not (and cannot) rebind the reference. The overload provided here changes the referenced data; not the references themselves. Such a distinction is important.

Hope this helps.

like image 43
WhozCraig Avatar answered Oct 19 '22 23:10

WhozCraig


Because it is illegal in C++ to reassign to a reference.

int &a = some_int;
a = some_other_int; // value copied not reference
a = some_int; // value copied not reference

When you use assignation operator (generated by compiler), it blindly does the copy of objects and thus try to reassign to your reference and hence is invalid.

When you say a2 = a1;, compiler would try to reassign a1.r to a2.r making it fail at compile time because it is ill-formation.

You can think of a reference as an automatically dereferenced constant pointer. So the line a2 = a1; will remain ill-formatted for the same reason as for the class below.

struct A
{
  A(int *var) : p(var) {}
  int * const p;
};
like image 24
Mohit Jain Avatar answered Oct 19 '22 22:10

Mohit Jain