22.3 — Move constructors and move assignment

Related content

Notably, this means that pointers will be copied, not moved!

Move functions should always leave both objects in a valid state

cppreference.com

Move assignment operator.

(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
/ types
types
Members
pointer
-declarations
(C++11)
specifier
specifier
Special member functions
(C++11)
(C++11)
Inheritance
specifier (C++11)
specifier (C++11)

A move 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, possibly mutating the argument.

Syntax Explanation Implicitly-declared move assignment operator Implicitly-defined move assignment operator Deleted move assignment operator Trivial move assignment operator Eligible move assignment operator Notes Example Defect reports See also

[ edit ] Syntax

For the formal move assignment operator syntax, see function declaration . The syntax list below only demonstrates a subset of all valid move assignment operator syntaxes.

return-type parameter-list  (1)
return-type parameter-list  function-body (2)
return-type parameter-list-no-default  (3)
return-type parameter-list  (4)
return-type class-name  parameter-list  function-body (5)
return-type class-name  parameter-list-no-default  (6)
class-name - the class whose move assignment operator is being declared, the class type is given as in the descriptions below
parameter-list - a of only one parameter, which is of type , const T&&, volatile T&& or const volatile T&&
parameter-list-no-default - a of only one parameter, which is of type , const T&&, volatile T&& or const volatile T&& and does not have a default argument
function-body - the of the move assignment operator
return-type - any type, but is favored in order to be consistent with scala types

[ edit ] Explanation

The move assignment operator is called whenever it is selected by overload resolution , e.g. when an object appears on the left-hand side of an assignment expression, where the right-hand side is an rvalue of the same or implicitly convertible type.

Move assignment operators typically transfer the resources held by the argument (e.g. pointers to dynamically-allocated objects, file descriptors, TCP sockets, thread handles, etc.), rather than make copies of them, and leave the argument in some valid but otherwise indeterminate state. Since move assignment doesn’t change the lifetime of the argument, the destructor will typically be called on the argument at a later point. For example, move-assigning from a std::string or from a std::vector may result in the argument being left empty. A move assignment is less, not more restrictively defined than ordinary assignment; where ordinary assignment must leave two copies of data at completion, move assignment is required to leave only one.

[ edit ] Implicitly-declared move assignment operator

If no user-defined move assignment operators are provided for a class type, and all of the following is true:

  • there are no user-declared copy constructors ;
  • there are no user-declared move constructors ;
  • there are no user-declared copy assignment operators ;
  • there is no user-declared destructor ,

then the compiler will declare a move assignment operator as an inline public member of its class with the signature T & T :: operator = ( T && ) .

A class can have multiple move assignment operators, e.g. both T & T :: operator = ( const T && ) and T & T :: operator = ( T && ) . If some user-defined move assignment operators are present, the user may still force the generation of the implicitly declared move assignment operator with the keyword default .

The implicitly-declared move assignment operator has an exception specification as described in dynamic exception specification (until C++17) noexcept specification (since C++17) .

Because some assignment operator (move or copy) 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 move assignment operator

If the implicitly-declared move 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 move assignment operator copies the object representation (as by std::memmove ).

For non-union class types, the move assignment operator performs full member-wise move assignment of the object's direct bases and immediate non-static members, in their declaration order, using built-in assignment for the scalars, memberwise move-assignment for arrays, and move assignment operator for class types (called non-virtually).

The implicitly-defined move assignment operator for a class is if

is a , and that is of class type (or array thereof), the assignment operator selected to move that member is a constexpr function.
(since C++14)
(until C++23)

The implicitly-defined move assignment operator for a class is .

(since C++23)

As with copy assignment, 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 move assignment operator:

[ edit ] Deleted move assignment operator

The implicitly-declared or defaulted move assignment operator for class T is defined as deleted 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 move 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.

A deleted implicitly-declared move assignment operator is ignored by overload resolution .

[ edit ] Trivial move assignment operator

The move 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 move assignment operator selected for every direct base of T is trivial;
  • the move assignment operator selected for every non-static class type (or array of class type) member of T is trivial.

A trivial move assignment operator performs the same action as the trivial copy assignment operator, that is, makes a copy of the object representation as if by std::memmove . All data types compatible with the C language are trivially move-assignable.

[ edit ] Eligible move assignment operator

A move assignment operator is eligible if it is not deleted.

(until C++20)

A move assignment operator is eligible if all following conditions are satisfied:

(if any) are satisfied. than any other move assignment operator.
(since C++20)

Triviality of eligible move 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 move assignment operator (same applies to copy assignment ).

See assignment operator overloading for additional detail on the expected behavior of a user-defined move-assignment operator.

[ edit ] Example

[ 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 the conditions where defaulted move assignment operators are
defined as deleted did not consider multi-dimensional array types
consider these types
C++11 a defaulted move assignment operator that would
call a non-trivial copy assignment operator was
deleted; a defaulted move assignment operator that
is deleted still participated in overload resolution
allows call to such
copy assignment
operator; made ignored
in overload resolution
C++11 specification for a defaulted move assignment operator
involving a virtual base class was missing
added
C++11 a volatile subobject made of a defaulted
move assignment operator non-trivial ( )
triviality not affected
C++11 a defaulted move assignment operator for class
was not defined as deleted if is abstract and has
non-move-assignable direct virtual base classes
the operator is defined
as deleted in this case
C++20 a move assignment operator was not eligible if there
is another move assignment operator which is more
constrained but does not satisfy its associated constraints
it can be eligible in this case
C++11 the implicitly-defined move assignment operator for
union types did not copy the object representation
they copy the object
representation

[ edit ] See also

  • constructor
  • converting constructor
  • copy assignment
  • copy constructor
  • default constructor
  • aggregate initialization
  • constant initialization
  • copy initialization
  • default initialization
  • direct initialization
  • list initialization
  • reference initialization
  • value initialization
  • zero initialization
  • 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 4 September 2024, at 07:11.
  • Privacy policy
  • About cppreference.com
  • Disclaimers

Powered by MediaWiki

A blog about C++ programming

Move Semantics: The Basics

Move Semantics

Move semantics was a new addition to C++ that arrived with C++ 11. Newer language standards have continued to expand and improve it. The feature is quite simple, but often misunderstood. I’m often reminded of that when I’m interviewing programmers.

Who will Find this Article Useful?

In this article I will cover all the basics of move semantics. This information will be useful for people that have never used move semantics but for people that are somehow familiar with the topic and use cases but don’t necessary use move semantics very often. The article will also be useful for people that want to dig deeper into the feature. And it will be useful for people that want to refresh their memory.

To benefit from this article to the fullest, you will need a good understanding of how copy constructors and assignment operators work, and you need to have a basic understanding of types and type casting.

1 – The case for Move Semantics

Before we look at the definition of move semantics, let us look at an example that will set up the premise of why move semantics exist.

1.1 – Setting the example

Let us assume that we are going to implement a struct that represents a memory block on the heap. The only thing this struct is responsible for is allocating the memory on construction and deallocating it on destruction. We can imagine that this struct is used by a complex memory allocation system. Let’s say that system is managing many instances of our struct, in other words, it is managing many memory buffers.

Here is the declaration of our struct:

We need to keep the example simple. And variables that could be needed for a robust solution, like used or free bytes and masks of all sorts, are out of the scope of this example.

1.2 – Using the Memory Buffer

Now let us also imagine that there is a free utility function that creates an array of buffers and returns the array. We can assume that this function is used by the complex memory allocation system in order to pre-allocate memory pools of different sizes.

Before C++ 11, no one would write this function in this way. Output parameters as pointer or reference will be used instead. This will make the function more complicated to implement, maintain and use. To explain why this was the case, let us have a look of how the “CreateMemoryPool” function is used. Let us assume that a bunch of pools of various sizes are created by the memory system in an “InitializePools” member function.

We will assume that we are not using any C++ 11 or newer additions to the language. We will also assume that for whatever reason the compiler will decide not to use Copy Elision to omit the copy of the return value of the “CreateMemoryPool(…)” function.

With all of these assumptions in play, calling the “CreateMemoryPool(…)” function will create a temporary return variable that will be used to assign to the member variables via the copy assignment operator of the std::vector. In other words, we are going to do a deep copy. This is very suboptimal way to write such code.

1.3 – The problem: deep copies can be very expensive

The problem with this scenario is that the local pool variable in the “CreateMemoryPool(…)” function, that stored the result of the function, will be copied into the m_PagePool and then destroyed. We are wasting a lot of cycles that way by executing extra instructions. We are also wasting cycles by allocating and deallocating memory (which is quite slow, generally speaking).

Before C++ 11, we would often reach for one of the following to minimize the allocations/deallocations caused by local and temporary variables:

  • Pass a pointer or a reference to the m_PagePool as input to the “CreateMemoryPool(…)” and let the function directly push back into the m_PagePool. In this way “CreateMemoryPool(…)” can return void, and the function is going to work directly on the variable that will store the final result of the function. And in this way we avoid copies. The first drawback is the extra parameter that is passed to the function, adding complexity. For example, doing this creates ambiguity when it comes to responsibility for the input state of that vector. Is it the callers responsibility to ensure that the vector is empty when invoking the function or will the function itself clear the vector? The second is the fact that passing a non-constant pointer or reference of the internal variable m_PagePool makes our code less safe because anyone can write code that does something bad to m_PagePool and the caller of “CreateMemoryPool(…)” loses all guarantees.
  • We can change the result of the function to return a vector of pointers to memory buffers, like so: vector<MemoryBuffer*>. This way we only copy the pointers when the “CreateMemoryPool(…)” function returns and there is no deep copying going on and no extra allocations/deallocations. The drawback to this is now the owner of the m_PagePool needs to worry about manually deallocating the pointers held by the vector, because the vector won’t do it in it own. Of course, we can use a vector of some of smart pointers to automate that part as well, but that also adds complexity.

1.4 – Move semantics solves the possible performance issue with deep copies

What we really want to do is keep the “CreateMemoryPool(…)” function implementation as it is, simple and safe, and move the result of the function directly into the m_PagePool variable without doing a deep copy, as if we are transferring water from one glass directly into another. Furthermore, we are doing even more copying by using the “push_back” function of the vector class and we want the push_back to also behave as if we are transferring water from one glass directly into another. C++ 11 and move semantics allows us to do exactly that. In the following sections, we are going to explore what move semantics are.

2 – Definition of Move Semantics

Move semantics are typically used to “steal” the resources held by another variable of the same type (e.g. pointers to dynamically-allocated objects, file descriptors, TCP sockets, I/O streams, running threads, etc.) and leave the source variable in some valid state, rather than making a deep copy of them.

The two most common use cases for move semantics are :

  • Performance: converting an expensive deep copy operation into a cheap move, like moving the data from a source string into a target string without having to allocate/deallocate.
  • Ownership semantics: Implementing user defined data types for which copying is not allowed but moving is, like the std::unique_ptr.

3 – Lvalues, Rvalues and Xvalues

To understand how move semantics work under the hood, we need to define a few other terms. Let’s start by looking at a pseudo-code that represents an assignment statement:

The left side of the statement is what historically is called Lvalue. And the right side of the statement is what historically is called Rvalue. Of course, because of the general nature of C++ things are often more complicated. Rvalues can appear on the left side, and Lvalues on the right side. Why that is the case is not relevant for this article.

3.1 – Easy way to differentiate between Lvalues and Rvalues

You might think that the fact that Lvalues and Rvalues can appear on either side is very confusing. Fortunately, there is a very simple rule we can use to remove all this confusion. A rule that will allow us to easily classify Lvalues and Rvalues in C++.

If a variable has an identifier that you have chosen yourself, then it is an Lvalue. And if a variable does not have a name that you have deliberately selected, then it is an Rvalue. To demonstrate this rule, let’s look at the following code snippets:

Here is another example:

3.2 – Double ampersands(&&) and the new operators

Prior to C++ 11, Rvalues and Lvalues were indistinguishable. The following example code would trigger the copy constructor and the copy assignment operator of the std::vector.

This is the Copy Constructor and the Copy Assignment Operator that would have been used in both cases:

To solve this problem, C++ 11 introduced Rvalue references, denoted by a double ampersands (&&). With this addition, we can now have two different copy constructors and assignment operators. One for Lvalues and one for Rvalues.

The following code snippet shows the declaration of the copy and the move constructors:

The following code snippet shows the declaration of the copy and the move assignment operators:

We can now revisit the example from above. And we can examine how in the cases where we have an Rvalue on the right hand side, the new move constructor and move assignment operators will be called instead of the copy constructor and copy assignment.

4 – Declaring Move Constructor and Move Assignment Operator

Now we know that C++ 11 introduced Rvalue references, denoted by a double ampersands (&&). And we know that we can declare a move constructor and a move assignment operator using the Rvalue type. Let’s declare them for our MemoryBuffer struct:

5 – Defining Move Constructor and Move Assignment Operator

We now know how to declare the move constructor and move assignment operator. It is now time to define them and actually implement the useful move semantics.

What we are doing in the move constructor and the move assignment is identical, except we also need to take care of self assignment in the move assignment operator. Let’s examine what we are doing in the move constructor:

  • In the initializer list, we are copying the source m_Buffer pointer into our own internal m_Buffer pointer. This is a simple pointer copy and not a deep copy. At this point both the source and the internal m_Buffer pointers point to the same memory address.
  • Then, also in the initializer list, we are copying the variable holding the size of the source buffer into the internal m_SizeInBytes variable.
  • Then, in the move constructor body, we set the source buffer pointer to nullptr. Effectively leaving the source pointer in a valid state, but also at this point completing the process of stealing the resource. After this the internal m_Buffer pointer points to where the source m_Buffer pointer used to point.
  • Finally, we reset the m_SizeInBytes of the source to 0, effectively leaving the source MemoryBuffer in a valid state.

For completeness, here is the the entire MemoryBuffer struct:

6 – Move Semantics in Action

With the new knowledge we acquired about Lvalues and Rvalues, as well as with the implementation of the move constructor and move assignment operator, we can now revisit the example we started with and see move semantics in action.

First, let us make a small change in the “CreateMemoryPool(…)” function.

To take advantage of the new move semantics and variadic templates, in C++ 11 a new version of the vector::push_back was added to the standard library. I recommend that you check the documentation, but in a nutshell, emplace_back will construct the new MemoryBuffer right in the memory location where it will be stored by the vector and in this way reducing the need to deep copy.

And finally, let us look at the “InitializePools” member function. Notice that the code is unchanged, but the compiler will call the move assignment operator and avoid deep copy and the extra allocations/deallocations, that are quite slow.

7 – Automatic vs. Manual Move

Looking at the “MemoryAllocationSystem::Initialize()” function, we can easily conclude that if move semantics were available to the compiler and if the types in question (std::vector and MemorBuffer in this case) supports move semantics, the compiler will detect the opportunity to move instead of copy. The reason for this is that the compiler will be able to see that the local variable created and returned by the “CreateMemoryPool(…)” is in fact an Rvalue.

The compiler is unable to detect every move opportunity. We can create a situation where we, as programmers, might have the intent to move the content of one array into another array (for whatever reasons) but the compiler will not be able to automatically detect our intent to move and will fallback to a deep copy. This of course happens when we have the intention to move an Lvalue into another Lvalue. Here is an example:

By default, the compiler will correctly assume that we ask for a deep copy. And if we really want to move, then we need to help the compiler a bit and turn the right hand Lvalues into Rvalue. To explicitly tell the compiler what our intent is, C++ 11 introduced a helper function: std::move . To utilize this new helper function, we can change our example to the following:

All std::move does is a cast. It casts the “ pool1 ” variable from an Lvalue reference (&) to an Rvalue reference (&&). Doing so tells the compiler which assignment operator it should call, because the variable type changes. And of course this is all based on standard function overloading rules. In its core, the assignment operator is a function, which is overloaded for two different input types (Lvalue reference and Rvalue reference).

8 – Xvalue

The following is a bit of an extra context and not absolutely necessary for this article, but I would rather mention it. The “ pool1 ” variable, in the example above, is technically an Xvalue after the std::move is executed. For all intent and purposes, you can treat it as an Lvalue, but the language implementers need a technical term for it. It means expiring value and it denotes an Lvalue object that can be reused after a move from it was executed. There are exactly three things that can be done to an Xvalue:

  • Copy assign to the Xvalue, turning it into an Lvalue.
  • Move assign to the Xvalue, turning it into an Lvalue.
  • Call the destructor when the Xvalue goes out of scope.

9 – Special Operators’ Rules

We all know that sometimes the compiler will generate constructors and other special operators on its own. The good news is that there are rules for when the compiler will do that. And now with the new move constructor and move assignment operator, these rules have been updated. For completeness, it is worth mentioning the most important rules here.

Rule 1 : Default move operations are generated only if no copy operations or destructor is user defined. This is because C++ assumes that if you need a destructor or you manually implemented copy operations, or both, then you are dealing with some sort of resource that needs special treatment. And because it is a resource, you need to implement the move operations yourself because you, as the expert, know best how this resources should behave.

Rule 2 : Default copy operations are generated only if there is no user defined move operations. The reasons here are are the same as in Rule 1. Note that =default and =delete count as user defined.

Rule 3 : You don’t need to implement move semantics or even copy semantics manually if all of the internal member variables are of types that are movable or copyable. For example, if we were to change the “char* m_Buffer” in our MemoryBuffer class to “unique_ptr<char> m_Buffer”, then we do not need to implement the move semantics ourselves, because the unique_ptr<T> class already supports move semantics.

10 – Parameters Convention

Move semantics is an optimization that is only applicable to some use cases. In general prefer simple and conventional ways of passing information. The following table illustrates an accepted convention for passing parameters and what types you should use. When in doubt, always check it.

Move Semantics and Parameters Convention

11 – Forwarding a Reference

For completeness, I need to cover one last topic. One more function was introduced together with std::move in C++ 11. And it was std::forward.

std::forward is pretty simple as it has only one use case. Its purpose is to preserve the value type, regardless if it is Lvalue or Rvalue, and pass it on. This is also called perfect forwarding. Typically a function accepting an Rvalue will attempt to move it and invalidate it, and when this is not the case, we can use std::forwad to pass on the Rvalue down the call-stack. The following example illustrates the use case.

For completeness, it is worth mentioning that In the code example above the input “T&& inArg” is called Forwarding reference . Forwarding references are a special kind of references that preserve the value category of a function argument. In this case calling “std::forward<T>(inArg)” will preserve the input argument and will forward it as Lvalue it if the input is an Lvalue, or it will forward it as Rvalue if the input is an Rvalue.

12 – Conclusion

In general, the concept of move semantics is quite simple and as programmers we should learn how and when to use it. The concept is built based on two fundamental C++ concepts: types and function/operator overloading. The following is a list of takeaway:

  • Pre-C++ 11, value semantics sometimes lead to unnecessary and possibly expensive deep copy operations.
  • C++ 11 introduces Rvalue references to distinguish from Lvalue references. And it also introduces std::move to cast from Lvalue to Rvalue.
  • From C++ 11 on, temporary variables are treated as Rvalues.
  • Moving POD or structs composed of PODs will not give you any benefits. To get benefits from move semantics you need some kind of resource (e.g. pointers to dynamically-allocated objects, file descriptors, TCP sockets, I/O streams, running threads, etc.).

13 – Source Code

The source code containing the MemoryBuffer example is here (under MoveSemantics ). You do not need a Github account to download it. When you open the repository, click on the Code button and choose Donwload ZIP .

14 – Credit

Special thanks to my colleagues for spending their personal time proofreading, challenge this article and helping me to make it better. It is a pleasure working with every one of you!

  • Anton Andersson : Senior Gameplay Programmer at IO Interactive.
  • Nils Iver Holtar : Lead AI Programmer at IO Interactive.

Please consider sharing this post if you find the information useful.

' src=

Post navigation

Previous post.

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

  • 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.

Which to use: move assignment operator vs copy assignment operator

I don't seem to get why would you use the move assignment operator :

over, the copy assignment operator :

The move assignment operator takes an r-value reference only e.g.

In the copy assignment operator , other can be constructor using a copy constructor or a move constructor (if other is initialized with an rvalue, it could be move-constructed --if move-constructor defined--).

If it is copy-constructed , we will be doing 1 copy and that copy can't be avoided.

If it is move-constructed then the performance/behavior is identical to the one produced by the first overload.

My questions are:

1- Why would one want to implement the move assignment operator .

2- If other is constructed from an r-value then which assignment operator would the compiler choose to call? And why?

  • overload-resolution

Kam's user avatar

  • 1) less work, 2) it'd be ambiguous. –  Kerrek SB Commented Nov 6, 2014 at 5:20
  • So you are saying for 2) the first overload will be called? –  Kam Commented Nov 6, 2014 at 5:24
  • CLASSA & operator=(CLASSA && other); is a move assignment operator . Not sure how that changes what you are asking about. A copy assignment operator takes either a CLASSA or a const CLASSA& . –  Radiodef Commented Nov 6, 2014 at 5:25
  • @Kam: No. An ambiguous overload means that overload resolution fails when you try to use the overload, which in turn makes the program ill formed. –  Kerrek SB Commented Nov 6, 2014 at 5:27
  • The performance/behaviour will not be identical. There will be probably be one less move if you pass by r-value reference. Whether that matters will depend on how expensive it is to move CLASSA . –  Chris Drew Commented Nov 6, 2014 at 5:43

2 Answers 2

You are not comparing like-with-like

If you are writing a move-only type like std::unique_ptr then a move assignment operator would be your only choice.

The more typical case is where you have a copyable type in which case I think you have three options.

  • T& operator=(T const&)
  • T& operator=(T const&) and T& operator=(T&&)
  • T& operator=(T) and move

Note that having both the overloads you suggested in one class is not an option as it would be ambiguous.

Option 1 is the traditional C++98 option and will perform fine in most cases. However, if you need to optimize for r-values you could consider Option 2 and add a move assignment operator.

It is tempting to consider Option 3 and pass-by-value and then move which I think is what you are suggesting. In that case you only have to write one assignment operator. It accepts l-values and at the cost of only one extra move accepts r-values and many people will advocate this approach.

However, Herb Sutter pointed out in his "Back to the Basics! Essentials of Modern C++ Style" talk at CppCon 2014 that this option is problematic and can be much slower. In the case of l-values it will perform an unconditional copy and will not reuse any existing capacity. He provides numbers to backup his claims. The only exception is constructors where there is no existing capacity to reuse and you often have many parameters so pass by-value can reduce the number of overloads needed.

So I would suggest you start with Option 1 and move to Option 2 if you need to optimize for r-values.

Chris Drew's user avatar

Clearly, the two overloads are not equivalent:

  • The assignment operator taking an rvalue reference only works with rvalues are on the right-hand side of the expression. To also support lvalues, another overload, e.g., using T const& would be needed for copyable types. Of course, for move-only types, like std::unique_ptr<T> , defining this assignment operator is the appropriate choice.
  • The assignment operator taking a value covers both rvalue and lvalue assignments assuming the type in question is both copy- and move-constructible. Its canonical implementation is to call swap() to replace the object's state with the state from the right-hand side. It has the advantage that the copy/move construction of the argument can often be elided.

In any case, you wouldn't want to have both overloads in one class! When assigning from an lvalue, obviously, the version taking a value would be chosen (the other option isn't viable). However, both assignment operators are viable when assigning an rvalue, i.e., there would be an ambiguity. This can easily be verified by trying to compile this code:

To deal with a move- and copy construction separately you could define a pair of assignment operators using T&& and T const& as arguments. However, this results in having to implement two versions of essentially the same copy assignment while having just a T as argument requires just one copy assignment to be implemented.

Thus, there are two obvious choices:

  • For a move-only type you'd define T::operator= (T&&) .
  • For a copyable type you'd define T::operator=(T) .

Dietmar Kühl's user avatar

  • 2 Herb sutter points out that using pass by-value in this way can be much slower than pass by reference-to-const due to making an unconditional copy and not reusing existing capacity. –  Chris Drew Commented Nov 6, 2014 at 7:20

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++ c++11 overload-resolution 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

  • Is it a good idea to perform I2C Communication in the ISR?
  • "It never works" vs "It better work"
  • Why do Quantum Kernel Methods work when a large Hilbert space tends to make all samples orthogonal to each other?
  • Pull up resistor question
  • Did Babylon 4 actually do anything in the first shadow war?
  • How can I measure the speed of sound with an oscilloscope and ultrasonic sensor? (Currently getting low value.)
  • What does 'ex' mean in this context
  • Choose your own adventure style: medieval post-demon apocalypse
  • Is there a way to read lawyers arguments in various trials?
  • Etymology of 制度
  • Upstairs washer suds coming out of basement sink
  • How do you tip cash when you don't have proper denomination or no cash at all?
  • Is it safe to install programs other than with a distro's package manager?
  • In Lord Rosse's 1845 drawing of M51, was the galaxy depicted in white or black?
  • I'm rewriting a 2019 oneshot and am up to 37,000 words already. Should I make them chapters or keep it as a long oneshot?
  • How to connect 20 plus external hard drives to a computer?
  • Matrix Multiplication & Addition
  • 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?
  • Density of smooth functions in weighted Sobolev space
  • What is the importance of bilinear functions?
  • How can I play MechWarrior 2?
  • Does the USA plan to establish a military facility on Saint Martin's Island in the Bay of Bengal?
  • Confusion about time dilation
  • Why does this theta function value yield such a good Riemann sum approximation?

c move assignment vs move constructor

  • C++ Data Types
  • C++ Input/Output
  • C++ Pointers
  • C++ Interview Questions
  • C++ Programs
  • C++ Cheatsheet
  • C++ Projects
  • C++ Exception Handling
  • C++ Memory Management

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 existing objectThis operator is called when an already initialized object is assigned a new value from another existing object. 
It creates a separate memory block for the new object.It does not automatically create a separate memory block or new memory space. However, if the class involves dynamic memory management, the assignment operator must first release the existing memory on the left-hand side and then allocate new memory as needed to copy the data from the right-hand side.
It is an overloaded constructor.It is a bitwise operator. 
C++ compiler implicitly provides a copy constructor, if no copy constructor is defined in the class.A bitwise copy gets created, if the Assignment operator is not overloaded. 

className(const className &obj) {

// body 

}

 

className obj1, obj2;

obj2 = obj1;

Consider the following C++ program. 

Explanation: Here, t2 = t1;  calls the assignment operator , same as t2.operator=(t1); and   Test t3 = t1;  calls the copy constructor , same as Test t3(t1);

Must Read: When is a Copy Constructor Called in C++?

Please Login to comment...

Similar reads.

  • Discord Emojis List 2024: Copy and Paste
  • Best Adblockers for Twitch TV: Enjoy Ad-Free Streaming in 2024
  • PS4 vs. PS5: Which PlayStation Should You Buy in 2024?
  • Best Mobile Game Controllers in 2024: Top Picks for iPhone and Android
  • System Design Netflix | A Complete Architecture

Improve your Coding Skills with Practice

 alt=

What kind of Experience do you want to share?

IMAGES

  1. C++11 Tutorial: Introducing the Move Constructor and the Move

    c move assignment vs move constructor

  2. C++ : How to force std::sort to use move constructor and move

    c move assignment vs move constructor

  3. M.3

    c move assignment vs move constructor

  4. C++. Move constructor and move operator

    c move assignment vs move constructor

  5. C++ : Move Constructor, move vector between two objects using std::move

    c move assignment vs move constructor

  6. C++ : When to use Move Constructors/Assignments

    c move assignment vs move constructor

VIDEO

  1. Assignment Operator in C Programming

  2. C++ Programming Techniques: The Rule of Five

  3. Such a c*** move!

  4. Visual Studio C#

  5. 414 E 4th Apt C move out

  6. 8. MoveC command and WorkObject coordinate system

COMMENTS

  1. c++

    A move constructor is executed only when you construct an object. A move assignment operator is executed on a previously constructed object. It is exactly the same scenario as in the copy case. Foo foo = std::move(bar); // construction, invokes move constructor. foo = std::move(other); // assignment, invokes move assignment operator.

  2. Move Constructors and Move Assignment Operators (C++)

    This topic describes how to write a move constructor and a move assignment operator for a C++ class. A move constructor enables the resources owned by an rvalue object to be moved into an lvalue without copying. For more information about move semantics, see Rvalue Reference Declarator: &&. This topic builds upon the following C++ class ...

  3. 22.3

    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).

  4. c++

    Wikipedia Page on C++11 R-value references and move constructors. In C++11, in addition to copy constructors, objects can have move constructors. (And in addition to copy assignment operators, they have move assignment operators.) The move constructor is used instead of the copy constructor, if the object has type "rvalue-reference" (Type &&).

  5. Move constructors

    Triviality of eligible move constructors determines whether the class is an implicit-lifetime type, and whether the class is a trivially copyable type. [] NoteTo make the strong exception guarantee possible, user-defined move constructors should not throw exceptions. For example, std::vector relies on std::move_if_noexcept to choose between move and copy when the elements need to be relocated.

  6. Move Constructors in C++

    Syntax of Move Constructor in C++. The move constructor takes the rvalue reference to the object of the same class as parameter. ClassName (ClassName&& obj) {. data = obj.data; // Nulling out the pointer to the temporary data. obj.data = nullptr; } We transfer the ownership of the resources from the old object to the new object and nullify the ...

  7. Move assignment operator

    The move assignment operator is called whenever it is selected by overload resolution, e.g. when an object appears on the left-hand side of an assignment expression, where the right-hand side is an rvalue of the same or implicitly convertible type.. Move assignment operators typically transfer the resources held by the argument (e.g. pointers to dynamically-allocated objects, file descriptors ...

  8. std::move in Utility in C++

    Move Constructor And Semantics: The move constructor was introduced in C++11. The need or purpose of a move constructor is to steal or move as many resources as it can from the source (original) object, as fast as possible, because the source does not need to have a meaningful value anymore, and/or because it is going to be destroyed in a ...

  9. Move Semantics: The Basics

    3 - Lvalues, Rvalues and Xvalues. To understand how move semantics work under the hood, we need to define a few other terms. Let's start by looking at a pseudo-code that represents an assignment statement: L = R. The left side of the statement is what historically is called Lvalue.

  10. C++11 Tutorial: Introducing the Move Constructor and the Move

    Designing a Move Assignment Operator. A move assignment operator has the following signature: C& C::operator= (C&& other);//C++11 move assignment operator. A move assignment operator is similar to a copy constructor except that before pilfering the source object, it releases any resources that its object may own.

  11. Move Assignment Operator in C++ 11

    The move assignment operator was added in C++ 11 to further strengthen the move semantics in C++. It is like a copy assignment operator but instead of copying the data, this moves the ownership of the given data to the destination object without making any additional copies. The source object is left in a valid but unspecified state.

  12. PDF Move Semantics in C++

    -Aka move assignment operator and move constructor the last two special member functions. Definition: l-values vs r-values - l-values can appear on the left or right of an = Definition: l-values vs r-values - l-values can appear on the left or right of an = - x is an l-value

  13. What is The Move Assignment Operator In Modern C++?

    The Move Assignment Operator is one of the great features of Object-Oriented Programming in professional development. It complements features like the copy assignment operator, copy constructor, move constructor, and destructor. Since the C++11 standards, the move assignment operator is declared by using "operator=" and it allows you to move one object to another object. In this post,

  14. C++

    What does a Move Constructor Do. Move Constructors moves an object rather than copying it. Instead of making a Deep Copy, it moves the resource on the heap/free store. This differs from member ...

  15. Move assignment operator

    In the C++ programming language, the move assignment operator = is used for transferring a temporary object to an existing object. The move assignment operator, like most C++ operators, can be overloaded.Like the copy assignment operator it is a special member function.. If the move assignment operator is not explicitly defined, the compiler generates an implicit move assignment operator (C++ ...

  16. c++

    If you provide both a move constructor and a move assignment operator for your class, you can eliminate redundant code by writing the move constructor to call the move assignment operator. The following example shows a revised version of the move constructor that calls the move assignment operator: // Move constructor. : _data(NULL) , _length(0 ...

  17. Copy constructors and copy assignment operators (C++)

    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.

  18. How to Define a Move Constructor in C++?

    To define a move constructor in C++ use the below syntax: Syntax to Define Move Constructor in C++. className(className&& source) noexcept; Here, className is the name of our class. && indicates an rvalue reference to classname and source is the source object from which resources are being moved. noexcept specifier is used to indicate that the ...

  19. c++

    return *this; } is how one would implement both copy and move assignment at once using copy-and-swap. By re-using the copy and move constructors ( other is either copy-constructed or move-constructed), and you just swap this with other. other dies at the end of the function, taking with it the old state of this.

  20. c++

    The move assignment operator takes an r-value reference only e.g. CLASSA a1, a2, a3; a1 = a2 + a3; In the copy assignment operator, other can be constructor using a copy constructor or a move constructor (if other is initialized with an rvalue, it could be move-constructed --if move-constructor defined--). If it is copy-constructed, we will be ...

  21. Copy Constructor vs Assignment Operator in C++

    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 existing object. This operator is called when an already initialized object is assigned a new value from another existing object. It creates a separate memory block for ...