Assignment Operator Not Inherited C++ Compiler

Copy Constructors and Copy Assignment Operators (C++)

Note

Starting in C++11, two kinds of assignment are supported in the language: copy assignment and move assignment. In this article "assignment" means copy assignment unless explicitly stated otherwise. For information about move assignment, see Move Constructors and Move Assignment Operators (C++).

Both the assignment operation and the initialization operation cause objects to be copied.

  • Assignment: When one object's value is assigned to another object, the first object is copied to the second object. Therefore,

    causes the value of to be copied to .

  • Initialization: Initialization occurs when a new object is declared, when arguments are passed to functions by value, or when values are returned from functions by value.

    You can define the semantics of "copy" for objects of class type. For example, consider this code:

The preceding code could mean "copy the contents of FILE1.DAT to FILE2.DAT" or it could mean "ignore FILE2.DAT and make a second handle to FILE1.DAT." You must attach appropriate copying semantics to each class, as follows.

  • By using the assignment operator together with a reference to the class type as the return type and the parameter that is passed by reference—for example .

  • By using the copy constructor.

    If you do not declare a copy constructor, the compiler generates a member-wise copy constructor for you. If you do not declare a copy assignment operator, the compiler generates a member-wise copy assignment operator for you. Declaring a copy constructor does not suppress the compiler-generated copy assignment operator, nor vice versa. If you implement either one, we recommend that you also implement the other one so that the meaning of the code is clear.

    The copy constructor takes an argument of type class-name&, where class-name is the name of the class for which the constructor is defined. For example:

Note

Make the type of the copy constructor's argument const class-name& whenever possible. This prevents the copy constructor from accidentally changing the object from which it is copying. It also enables copying from const objects.

Compiler generated copy constructors

Compiler-generated copy constructors, like user-defined copy constructors, have a single argument of type "reference to class-name." An exception is when all base classes and member classes have copy constructors declared as taking a single argument of type constclass-name&. In such a case, the compiler-generated copy constructor's argument is also const.

When the argument type to the copy constructor is not const, initialization by copying a const object generates an error. The reverse is not true: If the argument is const, you can initialize by copying an object that is not const.

Compiler-generated assignment operators follow the same pattern with regard to const. They take a single argument of type class-name& unless the assignment operators in all base and member classes take arguments of type constclass-name&. In this case, the class's generated assignment operator takes a const argument.

Note

When virtual base classes are initialized by copy constructors, compiler-generated or user-defined, they are initialized only once: at the point when they are constructed.

The implications are similar to those of the copy constructor. When the argument type is not const, assignment from a const object generates an error. The reverse is not true: If a const value is assigned to a value that is not const, the assignment succeeds.

For more information about overloaded assignment operators, see Assignment.

Assignment Operators

What is “self assignment”?

Self assignment is when someone assigns an object to itself. For example,

Obviously no one ever explicitly does a self assignment like the above, but since more than one pointer or reference can point to the same object (aliasing), it is possible to have self assignment without knowing it:

This is only valid for copy assignment. Self-assignment is not valid for move assignment.

Why should I worry about “self assignment”?

If you don’t worry about self assignment, you’ll expose your users to some very subtle bugs that have very subtle and often disastrous symptoms. For example, the following class will cause a complete disaster in the case of self-assignment:

If someone assigns a object to itself, line #1 deletes both and since and are the same object. But line #2 uses , which is no longer a valid object. This will likely cause a major disaster.

The bottom line is that you the author of class are responsible to make sure self-assignment on a object is innocuous. Do not assume that users won’t ever do that to your objects. It is your fault if your object crashes when it gets a self-assignment.

Aside: the above has a second problem: If an exception is thrown while evaluating (e.g., an out-of-memory exception or an exception in ’s copy constructor), will be a dangling pointer — it will point to memory that is no longer valid. This can be solved by allocating the new objects before deleting the old objects.

This is only valid for copy assignment. Self-assignment is not valid for move assignment.

Okay, okay, already; I’ll handle self-assignment. How do I do it?

You should worry about self assignment every time you create a class. This does not mean that you need to add extra code to all your classes: as long as your objects gracefully handle self assignment, it doesn’t matter whether you had to add extra code or not.

We will illustrate the two cases using the assignment operator in the previous FAQ:

  1. If self-assignment can be handled without any extra code, don’t add any extra code. But do add a comment so others will know that your assignment operator gracefully handles self-assignment:

    Example 1a:

    Example 1b:

  2. If you need to add extra code to your assignment operator, here’s a simple and effective technique:

    Or equivalently:

By the way: the goal is not to make self-assignment fast. If you don’t need to explicitly test for self-assignment, for example, if your code works correctly (even if slowly) in the case of self-assignment, then do not put an test in your assignment operator just to make the self-assignment case fast. The reason is simple: self-assignment is almost always rare, so it merely needs to be correct - it does not need to be efficient. Adding the unnecessary statement would make a rare case faster by adding an extra conditional-branch to the normal case, punishing the many to benefit the few.

In this case, however, you should add a comment at the top of your assignment operator indicating that the rest of the code makes self-assignment is benign, and that is why you didn’t explicitly test for it. That way future maintainers will know to make sure self-assignment stays benign, or if not, they will need to add the test.

This is only valid for copy assignment. Self-assignment is not valid for move assignment.

I’m creating a derived class; should my assignment operators call my base class’s assignment operators?

Yes (if you need to define assignment operators in the first place).

If you define your own assignment operators, the compiler will not automatically call your base class’s assignment operators for you. Unless your base class’s assignment operators themselves are broken, you should call them explicitly from your derived class’s assignment operators (again, assuming you create them in the first place).

However if you do not create your own assignment operators, the ones that the compiler create for you will automatically call your base class’s assignment operators.

Example:

0 Replies to “Assignment Operator Not Inherited C++ Compiler”

Lascia un Commento

L'indirizzo email non verrà pubblicato. I campi obbligatori sono contrassegnati *