21.12 — Overloading the assignment operator

C++ Operator Overloading Guidelines

One of the nice features of C++ is that you can give special meanings to operators, when they are used with user-defined classes. This is called operator overloading . You can implement C++ operator overloads by providing special member-functions on your classes that follow a particular naming convention. For example, to overload the + operator for your class, you would provide a member-function named operator+ on your class.

  • = (assignment operator)
  • + - * (binary arithmetic operators)
  • += -= *= (compound assignment operators)
  • == != (comparison operators)

Here are some guidelines for implementing these operators. These guidelines are very important to follow, so definitely get in the habit early.

Assignment Operator =

The assignment operator has a signature like this: class MyClass { public: ... MyClass & operator=(const MyClass &rhs); ... } MyClass a, b; ... b = a; // Same as b.operator=(a);

Notice that the = operator takes a const-reference to the right hand side of the assignment. The reason for this should be obvious, since we don't want to change that value; we only want to change what's on the left hand side.

  • e = 42 assigns 42 to e , then returns e as the result
  • The value of e is then assigned to d , and then d is returned as the result
  • The value of d is then assigned to c , and then c is returned as the result

Now, in order to support operator chaining, the assignment operator must return some value. The value that should be returned is a reference to the left-hand side of the assignment.

Notice that the returned reference is not declared const . This can be a bit confusing, because it allows you to write crazy stuff like this: MyClass a, b, c; ... (a = b) = c; // What?? At first glance, you might want to prevent situations like this, by having operator= return a const reference. However, statements like this will work with primitive types. And, even worse, some tools actually rely on this behavior. Therefore, it is important to return a non- const reference from your operator= . The rule of thumb is, "If it's good enough for int s, it's good enough for user-defined data-types."

So, for the hypothetical MyClass assignment operator, you would do something like this: // Take a const-reference to the right-hand side of the assignment. // Return a non-const reference to the left-hand side. MyClass& MyClass::operator=(const MyClass &rhs) { ... // Do the assignment operation! return *this; // Return a reference to myself. } Remember, this is a pointer to the object that the member function is being called on. Since a = b is treated as a.operator=(b) , you can see why it makes sense to return the object that the function is called on; object a is the left-hand side.

But, the member function needs to return a reference to the object, not a pointer to the object. So, it returns *this , which returns what this points at (i.e. the object), not the pointer itself. (In C++, instances are turned into references, and vice versa, pretty much automatically, so even though *this is an instance, C++ implicitly converts it into a reference to the instance.)

Now, one more very important point about the assignment operator:

YOU MUST CHECK FOR SELF-ASSIGNMENT!

This is especially important when your class does its own memory allocation. Here is why: The typical sequence of operations within an assignment operator is usually something like this: MyClass& MyClass::operator=(const MyClass &rhs) { // 1. Deallocate any memory that MyClass is using internally // 2. Allocate some memory to hold the contents of rhs // 3. Copy the values from rhs into this instance // 4. Return *this } Now, what happens when you do something like this: MyClass mc; ... mc = mc; // BLAMMO. You can hopefully see that this would wreak havoc on your program. Because mc is on the left-hand side and on the right-hand side, the first thing that happens is that mc releases any memory it holds internally. But, this is where the values were going to be copied from, since mc is also on the right-hand side! So, you can see that this completely messes up the rest of the assignment operator's internals.

The easy way to avoid this is to CHECK FOR SELF-ASSIGNMENT. There are many ways to answer the question, "Are these two instances the same?" But, for our purposes, just compare the two objects' addresses. If they are the same, then don't do assignment. If they are different, then do the assignment.

So, the correct and safe version of the MyClass assignment operator would be this: MyClass& MyClass::operator=(const MyClass &rhs) { // Check for self-assignment! if (this == &rhs) // Same object? return *this; // Yes, so skip assignment, and just return *this. ... // Deallocate, allocate new space, copy values... return *this; } Or, you can simplify this a bit by doing: MyClass& MyClass::operator=(const MyClass &rhs) { // Only do assignment if RHS is a different object from this. if (this != &rhs) { ... // Deallocate, allocate new space, copy values... } return *this; } Remember that in the comparison, this is a pointer to the object being called, and &rhs is a pointer to the object being passed in as the argument. So, you can see that we avoid the dangers of self-assignment with this check.

  • Take a const-reference for the argument (the right-hand side of the assignment).
  • Return a reference to the left-hand side, to support safe and reasonable operator chaining. (Do this by returning *this .)
  • Check for self-assignment, by comparing the pointers ( this to &rhs ).

Compound Assignment Operators += -= *=

I discuss these before the arithmetic operators for a very specific reason, but we will get to that in a moment. The important point is that these are destructive operators, because they update or replace the values on the left-hand side of the assignment. So, you write: MyClass a, b; ... a += b; // Same as a.operator+=(b) In this case, the values within a are modified by the += operator.

How those values are modified isn't very important - obviously, what MyClass represents will dictate what these operators mean.

The member function signature for such an operator should be like this: MyClass & MyClass::operator+=(const MyClass &rhs) { ... } We have already covered the reason why rhs is a const-reference. And, the implementation of such an operation should also be straightforward.

But, you will notice that the operator returns a MyClass -reference, and a non-const one at that. This is so you can do things like this: MyClass mc; ... (mc += 5) += 3;

Don't ask me why somebody would want to do this, but just like the normal assignment operator, this is allowed by the primitive data types. Our user-defined datatypes should match the same general characteristics of the primitive data types when it comes to operators, to make sure that everything works as expected.

This is very straightforward to do. Just write your compound assignment operator implementation, and return *this at the end, just like for the regular assignment operator. So, you would end up with something like this: MyClass & MyClass::operator+=(const MyClass &rhs) { ... // Do the compound assignment work. return *this; }

As one last note, in general you should beware of self-assignment with compound assignment operators as well. Fortunately, none of the C++ track's labs require you to worry about this, but you should always give it some thought when you are working on your own classes.

Binary Arithmetic Operators + - *

The binary arithmetic operators are interesting because they don't modify either operand - they actually return a new value from the two arguments. You might think this is going to be an annoying bit of extra work, but here is the secret:

Define your binary arithmetic operators using your compound assignment operators.

There, I just saved you a bunch of time on your homeworks.

So, you have implemented your += operator, and now you want to implement the + operator. The function signature should be like this: // Add this instance's value to other, and return a new instance // with the result. const MyClass MyClass::operator+(const MyClass &other) const { MyClass result = *this; // Make a copy of myself. Same as MyClass result(*this); result += other; // Use += to add other to the copy. return result; // All done! } Simple!

Actually, this explicitly spells out all of the steps, and if you want, you can combine them all into a single statement, like so: // Add this instance's value to other, and return a new instance // with the result. const MyClass MyClass::operator+(const MyClass &other) const { return MyClass(*this) += other; } This creates an unnamed instance of MyClass , which is a copy of *this . Then, the += operator is called on the temporary value, and then returns it.

If that last statement doesn't make sense to you yet, then stick with the other way, which spells out all of the steps. But, if you understand exactly what is going on, then you can use that approach.

You will notice that the + operator returns a const instance, not a const reference. This is so that people can't write strange statements like this: MyClass a, b, c; ... (a + b) = c; // Wuh...? This statement would basically do nothing, but if the + operator returns a non- const value, it will compile! So, we want to return a const instance, so that such madness will not even be allowed to compile.

  • Implement the compound assignment operators from scratch, and then define the binary arithmetic operators in terms of the corresponding compound assignment operators.
  • Return a const instance, to prevent worthless and confusing assignment operations that shouldn't be allowed.

Comparison Operators == and !=

The comparison operators are very simple. Define == first, using a function signature like this: bool MyClass::operator==(const MyClass &other) const { ... // Compare the values, and return a bool result. } The internals are very obvious and straightforward, and the bool return-value is also very obvious.

The important point here is that the != operator can also be defined in terms of the == operator, and you should do this to save effort. You can do something like this: bool MyClass::operator!=(const MyClass &other) const { return !(*this == other); } That way you get to reuse the hard work you did on implementing your == operator. Also, your code is far less likely to exhibit inconsistencies between == and != , since one is implemented in terms of the other.

  • Sign In / Suggest an Article

Current ISO C++ status

Upcoming ISO C++ meetings

Upcoming C++ conferences

Compiler conformance status

CppCon 2024

September 15-20, Aurora, CO, USA

Meeting C++ 2024

November 14-16, Berlin, Germany

assignment operators

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 Fred object to itself, line #1 deletes both this->p_ and f.p_ since *this and f are the same object. But line #2 uses *f.p_ , which is no longer a valid object. This will likely cause a major disaster.

The bottom line is that you the author of class Fred are responsible to make sure self-assignment on a Fred 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 Fred::operator= (const Fred&) has a second problem: If an exception is thrown while evaluating new Wilma(*f.p_) (e.g., an out-of-memory exception or an exception in Wilma ’s copy constructor ), this->p_ 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.

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 :

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:

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 if 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 if 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 if test.

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.

Please Login to submit a recommendation.

If you don’t have an account, you can register for free.

  • Getting started with C++
  • Awesome Book
  • Awesome Community
  • Awesome Course
  • Awesome Tutorial
  • Awesome YouTube
  • Argument Dependent Name Lookup
  • Arithmitic Metaprogramming
  • Atomic Types
  • Basic input/output in c++
  • Basic Type Keywords
  • Bit Manipulation
  • Bit Operators
  • Build Systems
  • C incompatibilities
  • C++ Containers
  • C++ Debugging and Debug-prevention Tools & Techniques
  • C++ function "call by value" vs. "call by reference"
  • C++ Streams
  • C++11 Memory Model
  • Callable Objects
  • Classes/Structures
  • Client server examples
  • Common compile/linker errors (GCC)
  • Compiling and Building
  • Concurrency With OpenMP
  • Const Correctness
  • const keyword
  • Constant class member functions
  • Copy Elision
  • Copying vs Assignment
  • Curiously Recurring Template Pattern (CRTP)
  • Data Structures in C++
  • Date and time using header
  • Design pattern implementation in C++
  • Digit separators
  • Enumeration
  • Explicit type conversions
  • Expression templates
  • Floating Point Arithmetic
  • Flow Control
  • Fold Expressions
  • Friend keyword
  • Function Overloading
  • Function Template Overloading
  • Futures and Promises
  • Header Files
  • Implementation-defined behavior
  • Inline functions
  • Inline variables
  • Internationalization in C++
  • Layout of object types
  • Linkage specifications
  • Memory management
  • Metaprogramming
  • More undefined behaviors in C++
  • Move Semantics
  • mutable keyword
  • Non-Static Member Functions
  • One Definition Rule (ODR)
  • Operator Overloading
  • operator precedence
  • Optimization
  • Optimization in C++
  • Overload resolution
  • Parameter packs
  • Perfect Forwarding
  • Pimpl Idiom
  • Pointers to members
  • Polymorphism
  • Preprocessor
  • RAII: Resource Acquisition Is Initialization
  • Random number generation
  • Recursion in C++
  • Recursive Mutex
  • Refactoring Techniques
  • Regular expressions
  • Resource Management
  • Return Type Covariance
  • Returning several values from a function
  • RTTI: Run-Time Type Information
  • SFINAE (Substitution Failure Is Not An Error)
  • Side by Side Comparisons of classic C++ examples solved via C++ vs C++11 vs C++14 vs C++17
  • Singleton Design Pattern
  • Smart Pointers
  • Special Member Functions
  • Standard Library Algorithms
  • static_assert
  • std::atomics
  • std::forward_list
  • std::function: To wrap any element that is callable
  • std::integer_sequence
  • std::iomanip
  • std::optional
  • std::set and std::multiset
  • std::string
  • std::variant
  • std::vector
  • Storage class specifiers
  • Stream manipulators
  • The ISO C++ Standard
  • The Rule of Three, Five, And Zero
  • Rule of Five
  • Rule of Three
  • Rule of Zero
  • Self-assignment Protection
  • The This Pointer
  • Thread synchronization structures
  • Trailing return type
  • type deduction
  • Type Erasure
  • Type Inference
  • Type Keywords
  • Type Traits
  • Typedef and type aliases
  • Undefined Behavior
  • Unit Testing in C++
  • Unnamed types
  • Unspecified behavior
  • User-Defined Literals
  • Using declaration
  • Using std::unordered_map
  • Value and Reference Semantics
  • Value Categories
  • Variable Declaration Keywords
  • Virtual Member Functions

C++ The Rule of Three, Five, And Zero Self-assignment Protection

Fastest entity framework extensions.

When writing a copy assignment operator, it is very important that it be able to work in the event of self-assignment. That is, it has to allow this:

Self-assignment usually doesn't happen in such an obvious way. It typically happens via a circuitous route through various code systems, where the location of the assignment simply has two Person pointers or references and has no idea that they are the same object.

Any copy assignment operator you write must be able to take this into account.

The typical way to do so is to wrap all of the assignment logic in a condition like this:

Note: It is important to think about self-assignment and ensure that your code behaves correctly when it happens. However, self-assignment is a very rare occurrence and optimizing to prevent it may actually pessimize the normal case. Since the normal case is much more common, pessimizing for self-assignment may well reduce your code efficiency (so be careful using it).

As an example, the normal technique for implementing the assignment operator is the copy and swap idiom . The normal implementation of this technique does not bother to test for self-assignment (even though self-assignment is expensive because a copy is made). The reason is that pessimization of the normal case has been shown to be much more costly (as it happens more often).

Move assignment operators must also be protected against self-assignment. However, the logic for many such operators is based on std::swap , which can handle swapping from/to the same memory just fine. So if your move assignment logic is nothing more than a series of swap operations, then you do not need self-assignment protection.

If this is not the case, you must take similar measures as above.

Got any C++ Question?

pdf

  • Advertise with us
  • Cookie Policy
  • Privacy Policy

Get monthly updates about new articles, cheatsheets, and tricks.

  • Windows Programming
  • UNIX/Linux Programming
  • General C++ Programming
  • assignment operator and self assignment

  assignment operator and self assignment

assignment operator self assignment check

cppreference.com

Assignment operators.

(C++20)
(C++20)
(C++11)
(C++20)
(C++17)
(C++11)
(C++11)
General topics
(C++11)
-
-expression
block


/
(C++11)
(C++11)
(C++11)
(C++20)
(C++20)
(C++11)

expression
pointer
specifier

specifier (C++11)
specifier (C++11)
(C++11)

(C++11)
(C++11)
(C++11)
General
(C++11)
(C++20)
(C++26)
(C++11)
(C++11)
-expression
-expression
-expression
(C++11)
(C++11)
(C++17)
(C++20)
    

Assignment operators modify the value of the object.

Operator name  Syntax  Prototype examples (for class T)
Inside class definition Outside class definition
simple assignment Yes T& T::operator =(const T2& b);
addition assignment Yes T& T::operator +=(const T2& b); T& operator +=(T& a, const T2& b);
subtraction assignment Yes T& T::operator -=(const T2& b); T& operator -=(T& a, const T2& b);
multiplication assignment Yes T& T::operator *=(const T2& b); T& operator *=(T& a, const T2& b);
division assignment Yes T& T::operator /=(const T2& b); T& operator /=(T& a, const T2& b);
remainder assignment Yes T& T::operator %=(const T2& b); T& operator %=(T& a, const T2& b);
bitwise AND assignment Yes T& T::operator &=(const T2& b); T& operator &=(T& a, const T2& b);
bitwise OR assignment Yes T& T::operator |=(const T2& b); T& operator |=(T& a, const T2& b);
bitwise XOR assignment Yes T& T::operator ^=(const T2& b); T& operator ^=(T& a, const T2& b);
bitwise left shift assignment Yes T& T::operator <<=(const T2& b); T& operator <<=(T& a, const T2& b);
bitwise right shift assignment Yes T& T::operator >>=(const T2& b); T& operator >>=(T& a, const T2& b);

this, and most also return *this so that the user-defined operators can be used in the same manner as the built-ins. However, in a user-defined operator overload, any type can be used as return type (including void). can be any type including .
Definitions Assignment operator syntax Built-in simple assignment operator Assignment from an expression Assignment from a non-expression initializer clause Built-in compound assignment operator Example Defect reports See also

[ edit ] Definitions

Copy assignment replaces the contents of the object a with a copy of the contents of b ( b is not modified). For class types, this is performed in a special member function, described in copy assignment operator .

replaces the contents of the object a with the contents of b, avoiding copying if possible (b may be modified). For class types, this is performed in a special member function, described in .

(since C++11)

For non-class types, copy and move assignment are indistinguishable and are referred to as direct assignment .

Compound assignment replace the contents of the object a with the result of a binary operation between the previous value of a and the value of b .

[ edit ] Assignment operator syntax

The assignment expressions have the form

target-expr new-value (1)
target-expr op new-value (2)
target-expr - the expression to be assigned to
op - one of *=, /= %=, += -=, <<=, >>=, &=, ^=, |=
new-value - the expression (until C++11) (since C++11) to assign to the target
  • ↑ target-expr must have higher precedence than an assignment expression.
  • ↑ new-value cannot be a comma expression, because its precedence is lower.

If new-value is not an expression, the assignment expression will never match an overloaded compound assignment operator.

(since C++11)

[ edit ] Built-in simple assignment operator

For the built-in simple assignment, the object referred to by target-expr is modified by replacing its value with the result of new-value . target-expr must be a modifiable lvalue.

The result of a built-in simple assignment is an lvalue of the type of target-expr , referring to target-expr . If target-expr is a bit-field , the result is also a bit-field.

[ edit ] Assignment from an expression

If new-value is an expression, it is implicitly converted to the cv-unqualified type of target-expr . When target-expr is a bit-field that cannot represent the value of the expression, the resulting value of the bit-field is implementation-defined.

If target-expr and new-value identify overlapping objects, the behavior is undefined (unless the overlap is exact and the type is the same).

If the type of target-expr is volatile-qualified, the assignment is deprecated, unless the (possibly parenthesized) assignment expression is a or an .

(since C++20)

new-value is only allowed not to be an expression in following situations:

is of a , and new-value is empty or has only one element. In this case, given an invented variable t declared and initialized as T t = new-value , the meaning of x = new-value  is x = t. is of class type. In this case, new-value is passed as the argument to the assignment operator function selected by .   <double> z; z = {1, 2}; // meaning z.operator=({1, 2}) z += {1, 2}; // meaning z.operator+=({1, 2})   int a, b; a = b = {1}; // meaning a = b = 1; a = {1} = b; // syntax error
(since C++11)

In overload resolution against user-defined operators , for every type T , the following function signatures participate in overload resolution:

& operator=(T*&, T*);
volatile & operator=(T*volatile &, T*);

For every enumeration or pointer to member type T , optionally volatile-qualified, the following function signature participates in overload resolution:

operator=(T&, T);

For every pair A1 and A2 , where A1 is an arithmetic type (optionally volatile-qualified) and A2 is a promoted arithmetic type, the following function signature participates in overload resolution:

operator=(A1&, A2);

[ edit ] Built-in compound assignment operator

The behavior of every built-in compound-assignment expression target-expr   op   =   new-value is exactly the same as the behavior of the expression target-expr   =   target-expr   op   new-value , except that target-expr is evaluated only once.

The requirements on target-expr and new-value of built-in simple assignment operators also apply. Furthermore:

  • For + = and - = , the type of target-expr must be an arithmetic type or a pointer to a (possibly cv-qualified) completely-defined object type .
  • For all other compound assignment operators, the type of target-expr must be an arithmetic type.

In overload resolution against user-defined operators , for every pair A1 and A2 , where A1 is an arithmetic type (optionally volatile-qualified) and A2 is a promoted arithmetic type, the following function signatures participate in overload resolution:

operator*=(A1&, A2);
operator/=(A1&, A2);
operator+=(A1&, A2);
operator-=(A1&, A2);

For every pair I1 and I2 , where I1 is an integral type (optionally volatile-qualified) and I2 is a promoted integral type, the following function signatures participate in overload resolution:

operator%=(I1&, I2);
operator<<=(I1&, I2);
operator>>=(I1&, I2);
operator&=(I1&, I2);
operator^=(I1&, I2);
operator|=(I1&, I2);

For every optionally cv-qualified object type T , the following function signatures participate in overload resolution:

& operator+=(T*&, );
& operator-=(T*&, );
volatile & operator+=(T*volatile &, );
volatile & operator-=(T*volatile &, );

[ edit ] Example

Possible output:

[ edit ] Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DR Applied to Behavior as published Correct behavior
C++11 for assignments to class type objects, the right operand
could be an initializer list only when the assignment
is defined by a user-defined assignment operator
removed user-defined
assignment constraint
C++11 E1 = {E2} was equivalent to E1 = T(E2)
( is the type of ), this introduced a C-style cast
it is equivalent
to E1 = T{E2}
C++20 compound assignment operators for volatile
-qualified types were inconsistently deprecated
none of them
is deprecated
C++11 an assignment from a non-expression initializer clause
to a scalar value would perform direct-list-initialization
performs copy-list-
initialization instead
C++20 bitwise compound assignment operators for volatile types
were deprecated while being useful for some platforms
they are not
deprecated

[ edit ] See also

Operator precedence

Operator overloading

Common operators

a = b
a += b
a -= b
a *= b
a /= b
a %= b
a &= b
a |= b
a ^= b
a <<= b
a >>= b

++a
--a
a++
a--

+a
-a
a + b
a - b
a * b
a / b
a % b
~a
a & b
a | b
a ^ b
a << b
a >> b

!a
a && b
a || b

a == b
a != b
a < b
a > b
a <= b
a >= b
a <=> b

a[...]
*a
&a
a->b
a.b
a->*b
a.*b

function call
a(...)
comma
a, b
conditional
a ? b : c
Special operators

converts one type to another related type
converts within inheritance hierarchies
adds or removes -qualifiers
converts type to unrelated type
converts one type to another by a mix of , , and
creates objects with dynamic storage duration
destructs objects previously created by the new expression and releases obtained memory area
queries the size of a type
queries the size of a (since C++11)
queries the type information of a type
checks if an expression can throw an exception (since C++11)
queries alignment requirements of a type (since C++11)

for Assignment operators
  • Recent changes
  • Offline version
  • What links here
  • Related changes
  • Upload file
  • Special pages
  • Printable version
  • Permanent link
  • Page information
  • In other languages
  • This page was last modified on 25 January 2024, at 23:41.
  • Privacy policy
  • About cppreference.com
  • Disclaimers

Powered by MediaWiki

CS253: Software Development with C++

Spring 2022, self-assignment.

Colorado State University logo

Show Lecture.Self-assignment as a slide show.

CS253 Self-assignment

assignment operator self assignment check

This illustrates the danger of self-assignment.

That is, when an object containing pointers or other handles to external resources is assigned to itself, you’ve got to be careful in operator= , or you might destroy your data before you copy it to yourself.

Copy Constructor General Outline

When a class contains a handle to external data, the copy constructor generally follows this pattern:

  • Copy the resource from the other object to this object.

That is, don’t just copy the handle (pointer, file descriptor, etc.). Instead you have to make an actual copy of the resource (copy the memory from new , create a new temporary file and copy the contents, etc.).

Of course, this is a copy constructor, not an assignment operator, so there was no previous value. We are constructing .

Assignment Operator General Outline

When a class contains a handle to external data, the assignment operator ( operator= ) generally follows this pattern:

  • Get rid of the old external data ( delete memory, close network socket, delete temporary file, unlock semaphore, etc.).
  • This is a silly class that stores a float in dynamic memory.
  • It works—so far.

Try Copy Constructor

  • That failed because the default copy ctor just copied the pointer.
  • Both objects’ dtors tried to free the same pointer … boom!
  • We deserve that, because we didn’t follow the general outline for a copy constructor. We got the default copy ctor.

Fixed Copy Constructor

  • The new copy ctor allocated more space and copied the data, not just the pointer.

Try Assignment Operator

  • The default assignment operator has the same problem.
  • Also, relying upon the compiler-created operator= when you've written the copy ctor is deprecated.

Fix Assignment Operator

  • The assignment operator now allocates space & copies the data.
  • Whaaaaaaaaaat?

Explanation

What happens inside a = a ?

  • First, delete the old data.
  • Second, copy the new data (that we just freed).
  • We must copy the data, but, sometimes, we can’t  !
  • If this is self-assignment, don’t do anything.
  • How to detect that?
  • See if the address of the left-hand-side ( this ) equals the address of the right-hand-side ( &rhs ).
  • The & in the declaration const HeapFloat &rhs means “reference to”, whereas the & in the expression   this != &rhs means ”address of”.

This Sounds Silly

  • Yeah, but, … so what? Nobody will ever really do that.
  • Not explicitly, no. But it might happen indirectly.
  • Find the smallest element.
  • Swap it with the first element.
  • What if the first element is the smallest element?
  • You’ll try to assign [0] to [0] ! Self-assignment!

Not very DRY

  • new float (*rhs.data) appears twice— WET !

The copy ctor calls operator= ; as complex objects often do. Initialize data = nullptr so the initial delete data is ok.

  • Trending Now
  • Foundational Courses
  • Data Science
  • Practice Problem
  • Machine Learning
  • System Design
  • DevOps Tutorial

Assignment Operators in Programming

Assignment operators in programming are symbols used to assign values to variables. They offer shorthand notations for performing arithmetic operations and updating variable values in a single step. These operators are fundamental in most programming languages and help streamline code while improving readability.

Table of Content

What are Assignment Operators?

  • Types of Assignment Operators
  • Assignment Operators in C
  • Assignment Operators in C++
  • Assignment Operators in Java
  • Assignment Operators in Python
  • Assignment Operators in C#
  • Assignment Operators in JavaScript
  • Application of Assignment Operators

Assignment operators are used in programming to  assign values  to variables. We use an assignment operator to store and update data within a program. They enable programmers to store data in variables and manipulate that data. The most common assignment operator is the equals sign ( = ), which assigns the value on the right side of the operator to the variable on the left side.

Types of Assignment Operators:

  • Simple Assignment Operator ( = )
  • Addition Assignment Operator ( += )
  • Subtraction Assignment Operator ( -= )
  • Multiplication Assignment Operator ( *= )
  • Division Assignment Operator ( /= )
  • Modulus Assignment Operator ( %= )

Below is a table summarizing common assignment operators along with their symbols, description, and examples:

OperatorDescriptionExamples
= (Assignment)Assigns the value on the right to the variable on the left.  assigns the value 10 to the variable x.
+= (Addition Assignment)Adds the value on the right to the current value of the variable on the left and assigns the result to the variable.  is equivalent to 
-= (Subtraction Assignment)Subtracts the value on the right from the current value of the variable on the left and assigns the result to the variable.  is equivalent to 
*= (Multiplication Assignment)Multiplies the current value of the variable on the left by the value on the right and assigns the result to the variable.  is equivalent to 
/= (Division Assignment)Divides the current value of the variable on the left by the value on the right and assigns the result to the variable.  is equivalent to 
%= (Modulo Assignment)Calculates the modulo of the current value of the variable on the left and the value on the right, then assigns the result to the variable.  is equivalent to 

Assignment Operators in C:

Here are the implementation of Assignment Operator in C language:

Assignment Operators in C++:

Here are the implementation of Assignment Operator in C++ language:

Assignment Operators in Java:

Here are the implementation of Assignment Operator in java language:

Assignment Operators in Python:

Here are the implementation of Assignment Operator in python language:

Assignment Operators in C#:

Here are the implementation of Assignment Operator in C# language:

Assignment Operators in Javascript:

Here are the implementation of Assignment Operator in javascript language:

Application of Assignment Operators:

  • Variable Initialization : Setting initial values to variables during declaration.
  • Mathematical Operations : Combining arithmetic operations with assignment to update variable values.
  • Loop Control : Updating loop variables to control loop iterations.
  • Conditional Statements : Assigning different values based on conditions in conditional statements.
  • Function Return Values : Storing the return values of functions in variables.
  • Data Manipulation : Assigning values received from user input or retrieved from databases to variables.

Conclusion:

In conclusion, assignment operators in programming are essential tools for assigning values to variables and performing operations in a concise and efficient manner. They allow programmers to manipulate data and control the flow of their programs effectively. Understanding and using assignment operators correctly is fundamental to writing clear, efficient, and maintainable code in various programming languages.

Please Login to comment...

Similar reads.

  • Programming
  • Top Android Apps for 2024
  • Top Cell Phone Signal Boosters in 2024
  • Best Travel Apps (Paid & Free) in 2024
  • The Best Smart Home Devices for 2024
  • 15 Most Important Aptitude Topics For Placements [2024]

Improve your Coding Skills with Practice

 alt=

What kind of Experience do you want to share?

  • Stack Overflow for Teams Where developers & technologists share private knowledge with coworkers
  • Advertising & Talent Reach devs & technologists worldwide about your product, service or employer brand
  • OverflowAI GenAI features for Teams
  • OverflowAPI Train & fine-tune LLMs
  • Labs The future of collective knowledge sharing
  • About the company Visit the blog

Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Get early access and see previews of new features.

Templated assignment operator and self-check

I'm reading a book on template programming, and one of the examples they have code that does a self check in a templated assignment operator. Basically it's something like the following:

Now, from my understanding, since the templated assignment operator doesn't prevent the default assignment operator from being generated, for cases where O = T, the default assignment operator will always be selected over the templated version. That is, in this situation it will never be the case that O = T.

What I'm wondering is whether my understanding of this is correct. If it is, is there some sort of a tricky hierarchy (like if I derive Foo from something else or if it is derived from something else) where the assignment operator will print out "success"?

I've tried several things but I can't really get it to do that.

Thanks in advance

  • variable-assignment

vmpstr's user avatar

  • you are missing the return on operator=. Also, what have you tried? –  BЈовић Commented Oct 4, 2012 at 15:06
  • 1 why did you not try this before posting the question? –  Cheers and hth. - Alf Commented Oct 4, 2012 at 15:06
  • 1 Well, you can force it: ideone.com/W3zgy –  BoBTFish Commented Oct 4, 2012 at 15:07
  • Note that the test for self-reference in the templated operator= is broken. It will work only if the Foo<O> and the Foo<T> are located in exactly the same memory location, which is not necessarily true. –  David Rodríguez - dribeas Commented Oct 4, 2012 at 15:46
  • sorry, i edited the question.. yeah i typed it out here, but I do have one with a return code in my terminal... –  vmpstr Commented Oct 4, 2012 at 15:52

Either you're right, or both MSVC 11 and g++ 4.7.1 got it wrong.

I.e., normally that templated assignment operator will not be called: the automatically generated copy assignment operator will be called.

To output "success", do like this, and hope that compiler uses Empty Base class Optimization (EBO):

Cheers and hth. - Alf's user avatar

Your Answer

Reminder: Answers generated by artificial intelligence tools are not allowed on Stack Overflow. Learn more

Sign up or log in

Post as a guest.

Required, but never shown

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy .

Not the answer you're looking for? Browse other questions tagged c++ templates variable-assignment or ask your own question .

  • The Overflow Blog
  • The hidden cost of speed
  • The creator of Jenkins discusses CI/CD and balancing business with open source
  • Featured on Meta
  • Announcing a change to the data-dump process
  • Bringing clarity to status tag usage on meta sites
  • What does a new user need in a homepage experience on Stack Overflow?
  • Feedback requested: How do you use tag hover descriptions for curating and do...
  • Staging Ground Reviewer Motivation

Hot Network Questions

  • How do I safely download and run an older version of software for testing without interfering with the currently installed version?
  • Why is a USB memory stick getting hotter when connected to USB-3 (compared to USB-2)?
  • Why isn't a confidence level of anything >50% "good enough"?
  • Does a party have to wait 1d4 hours to start a Short Rest if no healing is available and an ally is only stabilized?
  • Thriller from the early to mid 1960's involving blackmailing an official over underage liason
  • Why is Haji Najibullah's case being heard in federal court in the Southern District of NY?
  • Issue with the roots of the Equation of Time
  • Does the USA plan to establish a military facility on Saint Martin's Island in the Bay of Bengal?
  • Why is notation in logic so different from algebra?
  • Why would autopilot be prohibited below 1000 AGL?
  • Should on use mutate or insert to update storage?
  • Could an empire rise by economic power?
  • What should I do if my student has quarrel with my collaborator
  • Upstairs washer suds coming out of basement sink
  • Is there an error in Lurie, HTT, Proposition 6.1.2.6.?
  • Why are poverty definitions not based off a person's access to necessities rather than a fixed number?
  • Can this dragon fly with a rider?
  • How can I measure the speed of sound with an oscilloscope and ultrasonic sensor? (Currently getting low value.)
  • Can you equip or unequip a weapon before or after a Bonus Action?
  • Is "She played good" a grammatically correct sentence?
  • quantulum abest, quo minus .
  • Word for when someone tries to make others hate each other
  • Why does the church of latter day saints not recognize the obvious sin of the angel Moroni according to the account of Joseph Smith's own words?
  • What would be a good weapon to use with size changing spell

assignment operator self assignment check

COMMENTS

  1. c++

    To answer my rhetorical question: It means that a well-designed assignment operator should not need to check for self-assignment. Assigning an object to itself should work correctly (i.e. have the end-effect of "doing nothing") without performing an explicit check for self-assignment.

  2. Self assignment check in assignment operator

    If we have an object say a1 of type Array and if we have a line like a1 = a1 somewhere, the program results in unpredictable behavior because there is no self assignment check in the above code. To avoid the above issue, self assignment check must be there while overloading assignment operator. For example, following code does self assignment check.

  3. c++

    I have always seen the recommendation that the check is done explicitly. You've been looking in the wrong places, see e.g. C++ Coding Standards by Sutter & Alexandrescu. Self-assignment is exceedingly rare in most programs, so an explicit check adds a small cost to every self-assignment even though the check is almost always false.

  4. c++

    The compiler will generate memberwise copying and assignment by calling each member's operator/constructor in turn. That works fine. Sometimes people belive that the self-assignment test is an optimization, but it can just as well be a pessimisation - adding an extra check to all assignments.

  5. 21.12

    Second, the self-assignment check may be omitted in classes that can naturally handle self-assignment. Consider this Fraction class assignment operator that has a self-assignment guard: ... Just like other constructors and operators, you can prevent assignments from being made by making your copy assignment operator private or using the delete ...

  6. C++ Assignment Operator Overloading

    In C++, assignment operator should be overloaded with self assignment check. For example, consider the following class Array and overloaded assignment operator function without self assignment check. // A sample class class Array { private: int *ptr; int size; public: Array&amp; operator = (const Array &amp;rhs); // constructors and other functions

  7. Assignment Operators In C++

    In C++, assignment operator should be overloaded with self assignment check. For example, consider the following class Array and overloaded assignment operator function without self assignment check. // A sample class class Array { private: int *ptr; int size; public: Array&amp; operator = (const Array &amp;rhs); // constructors and other functions

  8. C++ Operator Overloading Guidelines

    Now, one more very important point about the assignment operator: YOU MUST CHECK FOR SELF-ASSIGNMENT! This is especially important when your class does its own memory allocation. Here is why: The typical sequence of operations within an assignment operator is usually something like this: MyClass& MyClass::operator=(const MyClass &rhs) { // 1.

  9. Assignment Operators

    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: Fred& Fred::operator= (const Fred& f) {. // This gracefully handles self assignment. *p_ = *f.p_; return *this;

  10. The assignment operator

    The steps in writing our own assignment operator are the following: Check for self-assignment. Delete old memory. Allocate new memory. Copy the data. Return *this. Notice the worry about self-assignment, as in "A = A". We need to check for this both to avoid unnecessary work and to avoid problems later when we delete the old memory.

  11. C++ Tutorial => Self-assignment Protection

    c++11. Move assignment operators must also be protected against self-assignment. However, the logic for many such operators is based on std::swap, which can handle swapping from/to the same memory just fine. So if your move assignment logic is nothing more than a series of swap operations, then you do not need self-assignment protection.

  12. assignment operator and self assignment

    Checking for self assignment can be necessary when the object contains raw pointers that have to be deep-copied, because the standard "delete the pointer in *this, reallocate it, and copy from the rhs object to *this" doesn't work since "delete the pointer in *this" would also delete the pointer in rhs in the self-assignment case.

  13. CS253

    Assignment Operator General Outline. When a class contains a handle to external data, the assignment operator ( operator=) generally follows this pattern: Get rid of the old external data ( delete memory, close network socket, delete temporary file, unlock semaphore, etc.). Copy the resource from the other object to this object.

  14. When should we write our own assignment operator in C++?

    In C++, assignment operator should be overloaded with self assignment check. For example, consider the following class Array and overloaded assignment operator function without self assignment check. // A sample class class Array { private: int *ptr; int size; public: Array&amp; operator = (const Array &amp;rhs); // constructors and other functions

  15. Assignment operators

    Correct behavior. CWG 1527. C++11. for assignments to class type objects, the right operand could be an initializer list only when the assignment is defined by a user-defined assignment operator. removed user-defined assignment constraint. CWG 1538. C++11. E1 ={E2} was equivalent to E1 = T(E2) (T is the type of E1), this introduced a C-style cast.

  16. What is the proper way to self assignment check in constructor?

    The first approach is more standard so if you see the second in practice it is likely a good developer will question if this is self-assignment safe or not. If you had a different structure: struct Foo {. std::shared_ptr<Bar> m_p; }; That would also be self-assignment safe if you just use m_p = src.m_p; .

  17. CS253

    Assignment Operator General Outline. When a class contains a handle to external data, the assignment operator ( operator=) generally follows this pattern: Get rid of the old external data ( delete memory, close network socket, delete temporary file, unlock semaphore, etc.). Copy the resource from the other object to this object.

  18. OOP54-CPP. Gracefully handle self-copy assignment

    The copy assignment operator uses std::move() rather than swap() to achieve safe self-assignment and a strong exception guarantee. The move assignment operator uses a move (via the method parameter) and swap. The move constructor is not strictly necessary, but defining a move constructor along with a move assignment operator is conventional for classes that support move operations.

  19. Assignment Operators in Programming

    Assignment operators are used in programming to assign values to variables. We use an assignment operator to store and update data within a program. They enable programmers to store data in variables and manipulate that data. The most common assignment operator is the equals sign (=), which assigns the value on the right side of the operator to ...

  20. Templated assignment operator and self-check

    I.e., normally that templated assignment operator will not be called: the automatically generated copy assignment operator will be called. To output "success", do like this, and hope that compiler uses Empty Base class Optimization (EBO): #include <iostream>. template <typename T>. class Foo;