This browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
Copy constructors and copy assignment operators (C++)
- 8 contributors
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. So, this code copies the value of b into a :
Initialization : Initialization occurs when you declare a new object, when you pass function arguments by value, or when you return by value from a function.
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 b a second handle to FILE1.DAT." You must attach appropriate copying semantics to each class, as follows:
Use an assignment operator operator= that returns a reference to the class type and takes one parameter that's passed by const reference—for example ClassName& operator=(const ClassName& x); .
Use the copy constructor.
If you don't declare a copy constructor, the compiler generates a member-wise copy constructor for you. Similarly, if you don't declare a copy assignment operator, the compiler generates a member-wise copy assignment operator for you. Declaring a copy constructor doesn't suppress the compiler-generated copy assignment operator, and vice-versa. If you implement either one, we recommend that you implement the other one, too. When you implement both, the meaning of the code is clear.
The copy constructor takes an argument of type ClassName& , where ClassName is the name of the class. For example:
Make the type of the copy constructor's argument const ClassName& whenever possible. This prevents the copy constructor from accidentally changing the copied object. It also lets you copy 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 const class-name & . In such a case, the compiler-generated copy constructor's argument is also const .
When the argument type to the copy constructor isn't const , initialization by copying a const object generates an error. The reverse isn't true: If the argument is const , you can initialize by copying an object that's not const .
Compiler-generated assignment operators follow the same pattern for const . They take a single argument of type ClassName& unless the assignment operators in all base and member classes take arguments of type const ClassName& . In this case, the generated assignment operator for the class takes a const argument.
When virtual base classes are initialized by copy constructors, whether compiler-generated or user-defined, they're initialized only once: at the point when they are constructed.
The implications are similar to the copy constructor. When the argument type isn't const , assignment from a const object generates an error. The reverse isn't true: If a const value is assigned to a value that's not const , the assignment succeeds.
For more information about overloaded assignment operators, see Assignment .
Was this page helpful?
Additional resources
- C++ Data Types
- C++ Input/Output
- C++ Pointers
- C++ Interview Questions
- C++ Programs
- C++ Cheatsheet
- C++ Projects
- C++ Exception Handling
- C++ Memory Management
Assignment Operators In C++
In C++, the assignment operator forms the backbone of many algorithms and computational processes by performing a simple operation like assigning a value to a variable. It is denoted by equal sign ( = ) and provides one of the most basic operations in any programming language that is used to assign some value to the variables in C++ or in other words, it is used to store some kind of information.
The right-hand side value will be assigned to the variable on the left-hand side. The variable and the value should be of the same data type.
The value can be a literal or another variable of the same data type.
Compound Assignment Operators
In C++, the assignment operator can be combined into a single operator with some other operators to perform a combination of two operations in one single statement. These operators are called Compound Assignment Operators. There are 10 compound assignment operators in C++:
- Addition Assignment Operator ( += )
- Subtraction Assignment Operator ( -= )
- Multiplication Assignment Operator ( *= )
- Division Assignment Operator ( /= )
- Modulus Assignment Operator ( %= )
- Bitwise AND Assignment Operator ( &= )
- Bitwise OR Assignment Operator ( |= )
- Bitwise XOR Assignment Operator ( ^= )
- Left Shift Assignment Operator ( <<= )
- Right Shift Assignment Operator ( >>= )
Lets see each of them in detail.
1. Addition Assignment Operator (+=)
In C++, the addition assignment operator (+=) combines the addition operation with the variable assignment allowing you to increment the value of variable by a specified expression in a concise and efficient way.
This above expression is equivalent to the expression:
2. Subtraction Assignment Operator (-=)
The subtraction assignment operator (-=) in C++ enables you to update the value of the variable by subtracting another value from it. This operator is especially useful when you need to perform subtraction and store the result back in the same variable.
3. Multiplication Assignment Operator (*=)
In C++, the multiplication assignment operator (*=) is used to update the value of the variable by multiplying it with another value.
4. Division Assignment Operator (/=)
The division assignment operator divides the variable on the left by the value on the right and assigns the result to the variable on the left.
5. Modulus Assignment Operator (%=)
The modulus assignment operator calculates the remainder when the variable on the left is divided by the value or variable on the right and assigns the result to the variable on the left.
6. Bitwise AND Assignment Operator (&=)
This operator performs a bitwise AND between the variable on the left and the value on the right and assigns the result to the variable on the left.
7. Bitwise OR Assignment Operator (|=)
The bitwise OR assignment operator performs a bitwise OR between the variable on the left and the value or variable on the right and assigns the result to the variable on the left.
8. Bitwise XOR Assignment Operator (^=)
The bitwise XOR assignment operator performs a bitwise XOR between the variable on the left and the value or variable on the right and assigns the result to the variable on the left.
9. Left Shift Assignment Operator (<<=)
The left shift assignment operator shifts the bits of the variable on the left to left by the number of positions specified on the right and assigns the result to the variable on the left.
10. Right Shift Assignment Operator (>>=)
The right shift assignment operator shifts the bits of the variable on the left to the right by a number of positions specified on the right and assigns the result to the variable on the left.
Also, it is important to note that all of the above operators can be overloaded for custom operations with user-defined data types to perform the operations we want.
Similar Reads
- Assignment Operators In C++ In C++, the assignment operator forms the backbone of many algorithms and computational processes by performing a simple operation like assigning a value to a variable. It is denoted by equal sign ( = ) and provides one of the most basic operations in any programming language that is used to assign 7 min read
- Move Assignment Operator in C++ 11 In C++ programming, we have a feature called the move assignment operator, which was introduced in C++11. It helps us handle objects more efficiently, especially when it comes to managing resources like memory. In this article, we will discuss move assignment operators, when they are useful and call 5 min read
- 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 improvin 7 min read
- Augmented Assignment Operators in Python An assignment operator is an operator that is used to assign some value to a variable. Like normally in Python, we write "a = 5" to assign value 5 to variable 'a'. Augmented assignment operators have a special role to play in Python programming. It basically combines the functioning of the arithmeti 4 min read
- Solidity - Assignment Operators Solidity is a high-level, statically-typed programming language for Ethereum smart contracts. Python, JavaScript, and C++ impact it. Solidity has several variable and value assignment operators. Solidity supports the following types of operators: Simple Assignment Operator.Arithmetic Assignment Oper 5 min read
- C++ Assignment Operator Overloading Prerequisite: Operator Overloading The assignment operator,"=", is the operator used for Assignment. It copies the right value into the left value. Assignment Operators are predefined to operate only on built-in Data types. Assignment operator overloading is binary operator overloading.Overloading a 4 min read
- Self assignment check in assignment operator 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& operator = (const Ar 2 min read
- Copy Constructor vs Assignment Operator in C++ Copy constructor and Assignment operator are similar as they are both used to initialize one object using another object. But, there are some basic differences between them: Copy constructor Assignment operator It is called when a new object is created from an existing object, as a copy of the exist 2 min read
- Bitwise Operators in C++ There are various Operators present in C++. Every Operator has a particular symbol as well as an Operation to perform. We have various categories of operators in C++. Arithmetic OperatorsRelational OperatorsLogical OperatorsAssignment OperatorsBitwise OperatorsIn this article, we will learn about th 6 min read
- C++ Arithmetic Operators Arithmetic Operators in C++ are used to perform arithmetic or mathematical operations on the operands. For example, ‘+’ is used for addition, ‘-‘ is used for subtraction, ‘*’ is used for multiplication, etc. In simple terms, arithmetic operators are used to perform arithmetic operations on variables 3 min read
- Operators in C++ An operator is a symbol that operates on a value to perform specific mathematical or logical computations. They form the foundation of any programming language. In C++, we have built-in operators to provide the required functionality. An operator operates the operands. For example, int c = a + b;He 13 min read
- Address Operator & in C The Address Operator in C is a special unary operator that returns the address of a variable. It is denoted as the Ampersand Symbol ( & ). This operator returns an integer value which is the address of its operand in the memory. We can use the address operator (&) with any kind of variables, 3 min read
- Default Assignment Operator and References in C++ We have discussed assignment operator overloading for dynamically allocated resources here. In this article, we discussed that when we don't write our own assignment operator, the compiler creates an assignment operator itself that does shallow copy and thus causes problems. The difference between s 2 min read
- Vector assign() in C++ STL In C++, the vector assign() is a built-in method used to assign the new values to the given vector by replacing old ones. It also modifies the size of the vector according to the given number of elements. Let’s take a look at an example that shows the how to use this function. [GFGTABS] C++ #include 4 min read
- When should we write our own assignment operator in C++? The answer is same as Copy Constructor. If a class doesn't contain pointers, then there is no need to write assignment operator and copy constructor. The compiler creates a default copy constructor and assignment operators for every class. The compiler created copy constructor and assignment operato 3 min read
- Conversion Operators in C++ In C++, the programmer abstracts real-world objects using classes as concrete types. Sometimes, it is required to convert one concrete type to another concrete type or primitive type implicitly. Conversion operators play an important role in such situations. It is similar to the operator overloading 4 min read
- C++ Increment and Decrement Operators Prerequisite: Operators in C++ What is a C++ increment Operator? The C++ increment operator is a unary operator. The symbol used to represent the increment operator is (++). The increment operator increases the value stored by the variable by 1. This operator is used for Numeric values only. There a 4 min read
- Unary Operators In C++ Unary operators in C++ are those operators that work on a single value (operand). They perform operations like changing a value's sign, incrementing or decrementing it by one, or obtaining its address. Examples include ++ for increment, -- for decrement, + for positive values, - for negative values, 8 min read
- set operator= in C++ STL The ‘=’ is an operator in C++ STL which copies (or moves) a set to another set and set::operator= is the corresponding operator function. There are three versions of this function: The first version takes reference of an set as an argument and copies it to an set. Syntax: ums1.operator=(set &set 2 min read
- Geeks Premier League
- Geeks Premier League 2023
Improve your Coding Skills with Practice
What kind of Experience do you want to share?
Mastering the Assignment Constructor in C++
An assignment constructor in C++ is a special type of constructor that initializes an object using the assignment operator, allowing for the copying of values from one object to another.
Here's a simple code snippet demonstrating an assignment constructor:
Understanding Assignment in C++
What is an assignment operation.
In C++, an assignment operation happens when you assign a value to an already initialized variable. Unlike initialization, which often occurs when the object is created, assignment takes an existing object and modifies its state. Understanding this distinction is crucial because it impacts how objects behave in your programs.
The Role of the Assignment Operator
The assignment operator (`=`) is a fundamental part of C++. It allows you to transfer the values of one object to another. However, it's essential to understand that C++ performs a shallow copy by default when you use the assignment operator on objects. This means that if your object contains pointers or dynamically allocated resources, both objects will point to the same memory location, potentially leading to double deletions or memory leaks .
Assignment Constructor: Definition and Purpose
What is an assignment constructor.
An assignment constructor isn't a technically formal term in C++, but it generally refers to the way you define the assignment operator within your class. The assignment operator function is critical for defining how one object can be assigned the values of another object of the same type.
When you do not provide a custom implementation of the assignment operator, C++ provides a default assignment operator , which does a shallow copy. This can create problems, especially if your class allocates resources dynamically.
Purpose of a Custom Assignment Constructor
A custom assignment operator allows you to define how to properly copy resources when one object is assigned to another. The absence of a well-defined assignment operator can lead to subtle bugs in larger applications, especially when dealing with dynamic resource allocation.
Syntax of Assignment Constructors
Basic syntax.
The syntax for declaring an assignment operator in C++ is as follows:
Note: Using `ClassName&` allows the function to return a reference to the current object, supporting chaining of assignments (e.g., `a = b = c`).
Returning `*this`
Returning `*this` from the assignment operator is crucial. It ensures that you return the current object rather than a copy of it. This enables the ability to chain assignments, thus making your code more readable and efficient.
Implementing an Assignment Constructor
Step-by-step guide.
To implement an assignment constructor, follow these steps:
- Check for self-assignment: Always check if you are attempting to assign the object to itself.
- Release existing resources if any are allocated within the object.
- Copy the contents from the `other` object appropriately.
- Return *this for chaining.
Code Example
Here's a complete example of a class with a defined assignment operator:
Deep Copy vs. Shallow Copy
The concept of shallow copy.
A shallow copy means that two objects share the same memory address for pointers. Here's a simplistic illustration:
In this example, `obj2` points to the same memory as `obj1.data`. If either object is destructed, you end up with dangling pointers.
The Concept of Deep Copy
In contrast, a deep copy duplicates the pointed-to data. This is what you implement in your assignment constructor:
This ensures that `obj1` and `obj2` own their separate copies of data, thus avoiding the risks of double deletion or memory corruption.
Best Practices for Assignment Constructors
Prevention of self-assignment.
Implementing a self-assignment check is essential since assigning an object to itself can lead to undefined behavior. You can prevent this by simply adding a check at the start of your assignment operator:
Exception Safety
Your assignment operator should be exception-safe. If an exception occurs during resource allocation (such as memory allocation failing), your program can terminate or leave your object in an inconsistent state. Employ the copy-and-swap idiom for safer assignment:
Avoiding Memory Leaks
Always ensure that dynamically allocated memory is deleted before reassigning. This prevents memory leaks that can accumulate if your program runs long-term or processes large arrays.
Common Errors and Debugging Tips
Identifying and fixing common mistakes.
Common mistakes when implementing assignment constructors include:
- Forgetting to check for self-assignment, which leads to corrupted data.
- Not freeing previously allocated resources, causing memory leaks.
Debugging Tips
Use debugging tools like Valgrind to catch memory errors or centralize resource management within smart pointers (like `std::unique_ptr` or `std::shared_ptr`). These tools can greatly simplify managing allocations and prevent standard mistakes.
In this article, we explored the assignment constructor in C++ , delving into its importance, implementation, and best practices. Understanding how to properly use assignment constructors is vital for writing robust and error-free C++ applications. As you continue to practice implementing assignment constructors, you'll build a firmer foundation in modern C++ programming, paving the way for more complex projects.
Additional Resources
For further reading on the intricacies of C++ and assignment constructor techniques, consider exploring foundational C++ programming books and participating in online forums where you can ask questions and engage with the community.
✨ Top Categories
- Data Structures
- Performance
- Development Tools
🎯 Popular Posts
Mastering assignment statement in c++: a quick guide.
Overloading Constructors C++ Made Simple
Mastering C++ Struct Constructor Made Easy
Understanding C++ Private Constructor: A Quick Guide
Class with Constructor in C++: A Quick Guide
Mastering C++ Move Constructor for Efficient Code
C++ Constructor Destructor: A Quick Guide to Mastery
Mastering Arithmetic Operators in C++: A Quick Guide
Custom Comparator C++: A Quick Guide to Crafting Comparisons
Default Constructor in C++: Unlocking the Basics
Sign up for free to CPP Scripts and be the first to get notified about updates.
Related posts
- 01 Get membership discounts
- 02 Be the first to know about new guides and scripts
- Advertise With Us
- Forgot password
- Terms of Service
- Privacy Policy
Navigation Menu
Search code, repositories, users, issues, pull requests..., provide feedback.
We read every piece of feedback, and take your input very seriously.
Saved searches
Use saved searches to filter your results more quickly.
To see all available qualifiers, see our documentation .
- Notifications You must be signed in to change notification settings
copy-constructors-and-copy-assignment-operators-cpp.md
Latest commit, file metadata and controls, copy constructors and copy assignment operators (c++).
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. So, this code copies the value of b into a :
Initialization : Initialization occurs when you declare a new object, when you pass function arguments by value, or when you return by value from a function.
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 b a second handle to FILE1.DAT." You must attach appropriate copying semantics to each class, as follows:
Use an assignment operator operator= that returns a reference to the class type and takes one parameter that's passed by const reference—for example ClassName& operator=(const ClassName& x); .
Use the copy constructor.
If you don't declare a copy constructor, the compiler generates a member-wise copy constructor for you. Similarly, if you don't declare a copy assignment operator, the compiler generates a member-wise copy assignment operator for you. Declaring a copy constructor doesn't suppress the compiler-generated copy assignment operator, and vice-versa. If you implement either one, we recommend that you implement the other one, too. When you implement both, the meaning of the code is clear.
The copy constructor takes an argument of type ClassName& , where ClassName is the name of the class. For example:
Make the type of the copy constructor's argument const ClassName& whenever possible. This prevents the copy constructor from accidentally changing the copied object. It also lets you copy 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 const class-name & . In such a case, the compiler-generated copy constructor's argument is also const .
When the argument type to the copy constructor isn't const , initialization by copying a const object generates an error. The reverse isn't true: If the argument is const , you can initialize by copying an object that's not const .
Compiler-generated assignment operators follow the same pattern for const . They take a single argument of type ClassName& unless the assignment operators in all base and member classes take arguments of type const ClassName& . In this case, the generated assignment operator for the class takes a const argument.
When virtual base classes are initialized by copy constructors, whether compiler-generated or user-defined, they're initialized only once: at the point when they are constructed.
The implications are similar to the copy constructor. When the argument type isn't const , assignment from a const object generates an error. The reverse isn't true: If a const value is assigned to a value that's not const , the assignment succeeds.
For more information about overloaded assignment operators, see Assignment .
22.3 — Move constructors and move assignment
In lesson 22.1 -- Introduction to smart pointers and move semantics , we took a look at std::auto_ptr, discussed the desire for move semantics, and took a look at some of the downsides that occur when functions designed for copy semantics (copy constructors and copy assignment operators) are redefined to implement move semantics.
In this lesson, we’ll take a deeper look at how C++11 resolves these problems via move constructors and move assignment.
Recapping copy constructors and copy assignment
First, let’s take a moment to recap copy semantics.
Copy constructors are used to initialize a class by making a copy of an object of the same class. Copy assignment is used to copy one class object to another existing class object. By default, C++ will provide a copy constructor and copy assignment operator if one is not explicitly provided. These compiler-provided functions do shallow copies, which may cause problems for classes that allocate dynamic memory. So classes that deal with dynamic memory should override these functions to do deep copies.
Returning back to our Auto_ptr smart pointer class example from the first lesson in this chapter, let’s look at a version that implements a copy constructor and copy assignment operator that do deep copies, and a sample program that exercises them:
In this program, we’re using a function named generateResource() to create a smart pointer encapsulated resource, which is then passed back to function main(). Function main() then assigns that to an existing Auto_ptr3 object.
When this program is run, it prints:
(Note: You may only get 4 outputs if your compiler elides the return value from function generateResource())
That’s a lot of resource creation and destruction going on for such a simple program! What’s going on here?
Let’s take a closer look. There are 6 key steps that happen in this program (one for each printed message):
- Inside generateResource(), local variable res is created and initialized with a dynamically allocated Resource, which causes the first “Resource acquired”.
- Res is returned back to main() by value. We return by value here because res is a local variable -- it can’t be returned by address or reference because res will be destroyed when generateResource() ends. So res is copy constructed into a temporary object. Since our copy constructor does a deep copy, a new Resource is allocated here, which causes the second “Resource acquired”.
- Res goes out of scope, destroying the originally created Resource, which causes the first “Resource destroyed”.
- The temporary object is assigned to mainres by copy assignment. Since our copy assignment also does a deep copy, a new Resource is allocated, causing yet another “Resource acquired”.
- The assignment expression ends, and the temporary object goes out of expression scope and is destroyed, causing a “Resource destroyed”.
- At the end of main(), mainres goes out of scope, and our final “Resource destroyed” is displayed.
So, in short, because we call the copy constructor once to copy construct res to a temporary, and copy assignment once to copy the temporary into mainres, we end up allocating and destroying 3 separate objects in total.
Inefficient, but at least it doesn’t crash!
However, with move semantics, we can do better.
Move constructors and move assignment
C++11 defines two new functions in service of move semantics: a move constructor, and a move assignment operator. Whereas the goal of the copy constructor and copy assignment is to make a copy of one object to another, the goal of the move constructor and move assignment is to move ownership of the resources from one object to another (which is typically much less expensive than making a copy).
Defining a move constructor and move assignment work analogously to their copy counterparts. However, whereas the copy flavors of these functions take a const l-value reference parameter (which will bind to just about anything), the move flavors of these functions use non-const rvalue reference parameters (which only bind to rvalues).
Here’s the same Auto_ptr3 class as above, with a move constructor and move assignment operator added. We’ve left in the deep-copying copy constructor and copy assignment operator for comparison purposes.
The move constructor and move assignment operator are simple. Instead of deep copying the source object ( a ) into the destination object (the implicit object), we simply move (steal) the source object’s resources. This involves shallow copying the source pointer into the implicit object, then setting the source pointer to null.
When run, this program prints:
That’s much better!
The flow of the program is exactly the same as before. However, instead of calling the copy constructor and copy assignment operators, this program calls the move constructor and move assignment operators. Looking a little more deeply:
- Res is returned back to main() by value. Res is move constructed into a temporary object, transferring the dynamically created object stored in res to the temporary object. We’ll talk about why this happens below.
- Res goes out of scope. Because res no longer manages a pointer (it was moved to the temporary), nothing interesting happens here.
- The temporary object is move assigned to mainres. This transfers the dynamically created object stored in the temporary to mainres.
- The assignment expression ends, and the temporary object goes out of expression scope and is destroyed. However, because the temporary no longer manages a pointer (it was moved to mainres), nothing interesting happens here either.
So instead of copying our Resource twice (once for the copy constructor and once for the copy assignment), we transfer it twice. This is more efficient, as Resource is only constructed and destroyed once instead of three times.
Related content
Move constructors and move assignment should be marked as noexcept . This tells the compiler that these functions will not throw exceptions.
We introduce noexcept in lesson 27.9 -- Exception specifications and noexcept and discuss why move constructors and move assignment are marked as noexcept in lesson 27.10 -- std::move_if_noexcept .
When are the move constructor and move assignment called?
The move constructor and move assignment are called when those functions have been defined, and the argument for construction or assignment is an rvalue. Most typically, this rvalue will be a literal or temporary value.
The copy constructor and copy assignment are used otherwise (when the argument is an lvalue, or when the argument is an rvalue and the move constructor or move assignment functions aren’t defined).
Implicit move constructor and move assignment operator
The compiler will create an implicit move constructor and move assignment operator if all of the following are true:
- There are no user-declared copy constructors or copy assignment operators.
- There are no user-declared move constructors or move assignment operators.
- There is no user-declared destructor.
These functions do a memberwise move, which behaves as follows:
- If member has a move constructor or move assignment (as appropriate), it will be invoked.
- Otherwise, the member will be copied.
Notably, this means that pointers will be copied, not moved!
The implicit move constructor and move assignment will copy pointers, not move them. If you want to move a pointer member, you will need to define the move constructor and move assignment yourself.
The key insight behind move semantics
You now have enough context to understand the key insight behind move semantics.
If we construct an object or do an assignment where the argument is an l-value, the only thing we can reasonably do is copy the l-value. We can’t assume it’s safe to alter the l-value, because it may be used again later in the program. If we have an expression “a = b” (where b is an lvalue), we wouldn’t reasonably expect b to be changed in any way.
However, if we construct an object or do an assignment where the argument is an r-value, then we know that r-value is just a temporary object of some kind. Instead of copying it (which can be expensive), we can simply transfer its resources (which is cheap) to the object we’re constructing or assigning. This is safe to do because the temporary will be destroyed at the end of the expression anyway, so we know it will never be used again!
C++11, through r-value references, gives us the ability to provide different behaviors when the argument is an r-value vs an l-value, enabling us to make smarter and more efficient decisions about how our objects should behave.
Key insight
Move semantics is an optimization opportunity.
Move functions should always leave both objects in a valid state
In the above examples, both the move constructor and move assignment functions set a.m_ptr to nullptr. This may seem extraneous -- after all, if a is a temporary r-value, why bother doing “cleanup” if parameter a is going to be destroyed anyway?
The answer is simple: When a goes out of scope, the destructor for a will be called, and a.m_ptr will be deleted. If at that point, a.m_ptr is still pointing to the same object as m_ptr , then m_ptr will be left as a dangling pointer. When the object containing m_ptr eventually gets used (or destroyed), we’ll get undefined behavior.
When implementing move semantics, it is important to ensure the moved-from object is left in a valid state, so that it will destruct properly (without creating undefined behavior).
Automatic l-values returned by value may be moved instead of copied
In the generateResource() function of the Auto_ptr4 example above, when variable res is returned by value, it is moved instead of copied, even though res is an l-value. The C++ specification has a special rule that says automatic objects returned from a function by value can be moved even if they are l-values. This makes sense, since res was going to be destroyed at the end of the function anyway! We might as well steal its resources instead of making an expensive and unnecessary copy.
Although the compiler can move l-value return values, in some cases it may be able to do even better by simply eliding the copy altogether (which avoids the need to make a copy or do a move at all). In such a case, neither the copy constructor nor move constructor would be called.
Disabling copying
In the Auto_ptr4 class above, we left in the copy constructor and assignment operator for comparison purposes. But in move-enabled classes, it is sometimes desirable to delete the copy constructor and copy assignment functions to ensure copies aren’t made. In the case of our Auto_ptr class, we don’t want to copy our templated object T -- both because it’s expensive, and whatever class T is may not even support copying!
Here’s a version of Auto_ptr that supports move semantics but not copy semantics:
If you were to try to pass an Auto_ptr5 l-value to a function by value, the compiler would complain that the copy constructor required to initialize the function parameter has been deleted. This is good, because we should probably be passing Auto_ptr5 by const l-value reference anyway!
Auto_ptr5 is (finally) a good smart pointer class. And, in fact the standard library contains a class very much like this one (that you should use instead), named std::unique_ptr. We’ll talk more about std::unique_ptr later in this chapter.
Another example
Let’s take a look at another class that uses dynamic memory: a simple dynamic templated array. This class contains a deep-copying copy constructor and copy assignment operator.
Now let’s use this class in a program. To show you how this class performs when we allocate a million integers on the heap, we’re going to leverage the Timer class we developed in lesson 18.4 -- Timing your code . We’ll use the Timer class to time how fast our code runs, and show you the performance difference between copying and moving.
On one of the author’s machines, in release mode, this program executed in 0.00825559 seconds.
Now let’s run the same program again, replacing the copy constructor and copy assignment with a move constructor and move assignment.
On the same machine, this program executed in 0.0056 seconds.
Comparing the runtime of the two programs, (0.00825559 - 0.0056) / 0.00825559 * 100 = 32.1% faster!
Deleting the move constructor and move assignment
You can delete the move constructor and move assignment using the = delete syntax in the exact same way you can delete the copy constructor and copy assignment.
If you delete the copy constructor, the compiler will not generate an implicit move constructor (making your objects neither copyable nor movable). Therefore, when deleting the copy constructor, it is useful to be explicit about what behavior you want from your move constructors. Either explicitly delete them (making it clear this is the desired behavior), or default them (making the class move-only).
The rule of five says that if the copy constructor, copy assignment, move constructor, move assignment, or destructor are defined or deleted, then each of those functions should be defined or deleted.
While deleting only the move constructor and move assignment may seem like a good idea if you want a copyable but not movable object, this has the unfortunate consequence of making the class not returnable by value in cases where mandatory copy elision does not apply. This happens because a deleted move constructor is still a declared function, and thus is eligible for overload resolution. And return by value will favor a deleted move constructor over a non-deleted copy constructor. This is illustrated by the following program:
Issues with move semantics and std::swap Advanced
In lesson 21.12 -- Overloading the assignment operator , we mentioned the copy and swap idiom. Copy and swap also works for move semantics, meaning we can implement our move constructor and move assignment by swapping resources with the object that will be destroyed.
This has two benefits:
- The persistent object now controls the resources that were previously under ownership of the dying object (which was our primary goal).
- The dying object now controls the resources that were previously under ownership of the persistent object. When the dying object actually dies, it can do any kind of cleanup required on those resources.
When you think about swapping, the first thing that comes to mind is usually std::swap() . However, implementing the move constructor and move assignment using std::swap() is problematic, as std::swap() calls both the move constructor and move assignment on move-capable objects. This will result in an infinite recursion issue.
You can see this happen in the following example:
This prints:
And so on… until the stack overflows.
You can implement the move constructor and move assignment using your own swap function, as long as your swap member function does not call the move constructor or move assignment. Here’s an example of how that can be done:
This works as expected, and prints:
cppreference.com
Copy assignment operator.
A copy assignment operator is a non-template non-static member function with the name operator = that can be called with an argument of the same class type and copies the content of the argument without mutating the argument.
[ edit ] Syntax
For the formal copy assignment operator syntax, see function declaration . The syntax list below only demonstrates a subset of all valid copy assignment operator syntaxes.
[ edit ] Explanation
The copy assignment operator is called whenever selected by overload resolution , e.g. when an object appears on the left side of an assignment expression.
[ edit ] Implicitly-declared copy assignment operator
If no user-defined copy assignment operators are provided for a class type, the compiler will always declare one as an inline public member of the class. This implicitly-declared copy assignment operator has the form T & T :: operator = ( const T & ) if all of the following is true:
- each direct base B of T has a copy assignment operator whose parameters are B or const B & or const volatile B & ;
- each non-static data member M of T of class type or array of class type has a copy assignment operator whose parameters are M or const M & or const volatile M & .
Otherwise the implicitly-declared copy assignment operator is declared as T & T :: operator = ( T & ) .
Due to these rules, the implicitly-declared copy assignment operator cannot bind to a volatile lvalue argument.
A class can have multiple copy assignment operators, e.g. both T & T :: operator = ( T & ) and T & T :: operator = ( T ) . If some user-defined copy assignment operators are present, the user may still force the generation of the implicitly declared copy assignment operator with the keyword default . (since C++11)
The implicitly-declared (or defaulted on its first declaration) copy assignment operator has an exception specification as described in dynamic exception specification (until C++17) noexcept specification (since C++17)
Because the copy assignment operator is always declared for any class, the base class assignment operator is always hidden. If a using-declaration is used to bring in the assignment operator from the base class, and its argument type could be the same as the argument type of the implicit assignment operator of the derived class, the using-declaration is also hidden by the implicit declaration.
[ edit ] Implicitly-defined copy assignment operator
If the implicitly-declared copy assignment operator is neither deleted nor trivial, it is defined (that is, a function body is generated and compiled) by the compiler if odr-used or needed for constant evaluation (since C++14) . For union types, the implicitly-defined copy assignment copies the object representation (as by std::memmove ). For non-union class types, the operator performs member-wise copy assignment of the object's direct bases and non-static data members, in their initialization order, using built-in assignment for the scalars, memberwise copy-assignment for arrays, and copy assignment operator for class types (called non-virtually).
[ edit ] Deleted copy assignment operator
An implicitly-declared or explicitly-defaulted (since C++11) copy assignment operator for class T is undefined (until C++11) defined as deleted (since C++11) if any of the following conditions is satisfied:
- T has a non-static data member of a const-qualified non-class type (or possibly multi-dimensional array thereof).
- T has a non-static data member of a reference type.
- T has a potentially constructed subobject of class type M (or possibly multi-dimensional array thereof) such that the overload resolution as applied to find M 's copy assignment operator
- does not result in a usable candidate, or
- in the case of the subobject being a variant member , selects a non-trivial function.
[ edit ] Trivial copy assignment operator
The copy assignment operator for class T is trivial if all of the following is true:
- it is not user-provided (meaning, it is implicitly-defined or defaulted);
- T has no virtual member functions;
- T has no virtual base classes;
- the copy assignment operator selected for every direct base of T is trivial;
- the copy assignment operator selected for every non-static class type (or array of class type) member of T is trivial.
A trivial copy assignment operator makes a copy of the object representation as if by std::memmove . All data types compatible with the C language (POD types) are trivially copy-assignable.
[ edit ] Eligible copy assignment operator
Triviality of eligible copy assignment operators determines whether the class is a trivially copyable type .
[ edit ] Notes
If both copy and move assignment operators are provided, overload resolution selects the move assignment if the argument is an rvalue (either a prvalue such as a nameless temporary or an xvalue such as the result of std::move ), and selects the copy assignment if the argument is an lvalue (named object or a function/operator returning lvalue reference). If only the copy assignment is provided, all argument categories select it (as long as it takes its argument by value or as reference to const, since rvalues can bind to const references), which makes copy assignment the fallback for move assignment, when move is unavailable.
It is unspecified whether virtual base class subobjects that are accessible through more than one path in the inheritance lattice, are assigned more than once by the implicitly-defined copy assignment operator (same applies to move assignment ).
See assignment operator overloading for additional detail on the expected behavior of a user-defined copy-assignment operator.
[ edit ] Example
[ edit ] defect reports.
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
[ edit ] See also
- converting constructor
- copy constructor
- copy elision
- default constructor
- aggregate initialization
- constant initialization
- copy initialization
- default initialization
- direct initialization
- initializer list
- list initialization
- reference initialization
- value initialization
- zero initialization
- move assignment
- move constructor
- 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 2 February 2024, at 15:13.
- Privacy policy
- About cppreference.com
- Disclaimers
IMAGES
VIDEO
COMMENTS
CPP // CPP Program to demonstrate the use of copy constructor // and assignment operator #include <iostream> #include <stdio.h> using namespace std; class Test ... But, there are some basic differences between them: Copy constructor Assignment operator It is called when a new object is created from an existing object, as a copy of the exist.
A copy constructor is used to initialize a previously uninitialized object from some other object's data.. A(const A& rhs) : data_(rhs.data_) {} For example: A aa; A a = aa; //copy constructor An assignment operator is used to replace the data of a previously initialized object with some other object's data.. A& operator=(const A& rhs) {data_ = rhs.data_; return *this;}
Use an assignment operator operator= that returns a reference to the class type and takes one parameter that's passed by const reference—for example ClassName& operator=(const ClassName& x);. Use the copy constructor. If you don't declare a copy constructor, the compiler generates a member-wise copy constructor for you.
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.
Copy constructor and Assignment operator are similar as they are both used to initialize one object using another object. But, there are some basic differences between them: Copy constructor Assignment operator It is called when a new object is created from an existing object, as a copy of the exist ... CPP; Corporate & Communications Address ...
Assignment Constructor: Definition and Purpose What is an Assignment Constructor? An assignment constructor isn't a technically formal term in C++, but it generally refers to the way you define the assignment operator within your class. The assignment operator function is critical for defining how one object can be assigned the values of another object of the same type.
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.
C++11 defines two new functions in service of move semantics: a move constructor, and a move assignment operator. Whereas the goal of the copy constructor and copy assignment is to make a copy of one object to another, the goal of the move constructor and move assignment is to move ownership of the resources from one object to another (which is typically much less expensive than making a copy).
Triviality of eligible copy assignment operators determines whether the class is a trivially copyable type. [] NoteIf both copy and move assignment operators are provided, overload resolution selects the move assignment if the argument is an rvalue (either a prvalue such as a nameless temporary or an xvalue such as the result of std::move), and selects the copy assignment if the argument is an ...
(continued) CTest b = CTest(5); literally states: call constructor for b, call constructor (5) for a temp, call assignment for b from the temp, and destroy the temp. in general, a c++ compiler is not allowed to make "top down" optimizations by assuming properties of constructors and operators. eg: a + b - b might be optimized to a if a and b ...