Copy constructors and copy assignment operators
starting with C + + 11, the language supports two types of allocations: copying assignments and moving assignments. In this article, "assignment" means copying an assignment unless there are other explicit declarations. Assignment operations and initialization operations cause the object to be copied.
Assignment: When you assign the value of one object to another object, the first object is copied to the second object. So
Causes the value of B to be copied into a.
Initialization: Declares a new object, a parameter passed by value to a function, or a value is returned from a function by a value.
You can define the semantics of "copy" for objects of class type. For example, consider this code:
Textfile A, B;
A.open ("FILE1.") DAT ");
B.open ("FILE2.") DAT ");
b = A;
The preceding code may indicate that "will FILE1." DAT content is copied to FILE2. DAT ", may also indicate" ignore FILE2. DAT and make B a FILE1. Another handle to DAT. " You must attach the appropriate replication semantics to each class, as shown below.
By using the assignment operator operator= with a reference to a class type as a parameter passed by a return type and a const reference (for example,,classname& operator= (const classname& x);).
By copying the constructor. For more information about the copy constructor, see declaring a constructor's rule.
If you do not declare a copy constructor, the compiler will generate the Member-wise copy constructor for you. If you do not declare a copy assignment operator, the compiler generates member-wise copy assignment operators for you. Declaring a copy constructor does not undo the compiler-generated copy assignment operator, and vice versa. If you implement one of the above, it is recommended that you also implement another item to make the meaning of your code clear.
Member assignments are described in more detail in member assignment and initialization.
The copy constructor takes an argument of type class-name&, where Class-name is the name of the class for which the constructor is defined. For example:
Spec1_copying_class_objects.cpp
class Window
{public
:
window (const window&);//Declare copy constructor.
// ...
};
int main ()
{
}
Description
Create the parameter const class-name& of the copy constructor of the type whenever possible. This prevents the copy constructor from accidentally changing the object from which it was copied. It also supports copying from a const object.
Compiler-generated constructors
A compiler-generated copy constructor, such as a user-defined copy constructor, has a single argument type "reference to Class-name". An exception is thrown when all base classes and member classes have a copy constructor declared to take a single parameter of the const class-name& type. In this case, the parameters of the copy constructor generated by the compiler are also const.
When the parameter type of the copy constructor is not const, initialization by copying the const object generates an error. Otherwise: If the parameter is const, you can initialize it by copying an object that is not a const.
The compiler-generated assignment operator follows the same pattern about Const. Unless the assignment operators in all base classes and member classes take parameters of the const class-name& type, they take a single parameter of the class-name& type. In this case, the generated assignment operator for the class takes the const parameter.
Description
When a virtual base class is initialized by a copy constructor (compiler-generated or user-defined), only those base classes are initialized once: when they are constructed.
Meaning is similar to the meaning of the copy constructor. Assigning a value from a Const object generates an error when the parameter type is not a const. Otherwise: If you assign a const value to a value that is not a const, the assignment succeeds.
Move constructors and move assignment operators
The following example is based on the C + + class Memoryblock used to manage memory buffers.
MemoryBlock.h #pragma once #include <iostream> #include <algorithm> class Memoryblock {public://Simp
Le constructor that initializes the resource. Explicit Memoryblock (size_t length): _length (length), _data (new Int[length]) {std::cout << "in Memoryblock (size_t).
Length = "<< _length <<". "<< Std::endl;
}//destructor. ~memoryblock () {std::cout << "in ~memoryblock ().
Length = "<< _length <<".
if (_data!= nullptr) {std::cout << "deleting resource.";
Delete the resource.
Delete[] _data;
} std::cout << Std::endl;
}//Copy constructor. Memoryblock (const memoryblock& Other): _length (Other._length), _data (new Int[other._length]) {Std::cout < < "in Memoryblock (const memoryblock&). Length = "<< other._length <<".
Copying resource. "<< Std::endl;
Std::copy (Other._data, Other._data + _length, _data); }//Copy assignment operator. memoryblock& operator= (const memoryblock& Other) {std::cout << ' in operator= (const memoryblock&). Length = "<< other._length <<".
Copying resource. "<< Std::endl;
if (this!= &other) {//Free the existing resource.
Delete[] _data;
_length = Other._length;
_data = new Int[_length];
Std::copy (Other._data, Other._data + _length, _data);
return *this;
}//Retrieves the length of the data resource.
size_t Length () const {return _length; } private:size_t _length;
The length of the resource. Int* _data;
The resource.
};
The following procedure describes how to write a move constructor and move an assignment operator for the sample C + + class.
Create a move constructor for C + +
defines an empty constructor method that takes a reference to the right value of a class type as an argument, as in the following example:
Memoryblock (memoryblock&& Other)
: _data (nullptr)
, _length (0)
{
}
In the move constructor, add the class data members from the source object to the object to be constructed:
_data = Other._data;
_length = Other._length;
Assigns the data members of the source object to the default values. This prevents the destructor from releasing resources (such as memory) multiple times:
Other._data = nullptr;
other._length = 0;
To create a move assignment operator for a C + + class
defines an empty assignment operator that takes a reference to the right value of a class type as a parameter and returns a reference to the class type, as shown in the following example:
memoryblock& operator= (memoryblock&& Other)
{
}
In the move assignment operator, if you try to assign an object to itself, you add a conditional statement that does not perform an operation.
In a conditional statement, free all resources, such as memory, from the object to which you want to assign a value.
The following example frees the _data member from the object to which you want to assign a value:
Free the existing resource.
Delete[] _data;
Perform steps 2 and 3 in the first procedure to transfer data members from the source object to the object to be constructed:
Copy the data pointer and its length from the
//source object.
_data = Other._data;
_length = other._length;
Release of the data pointer from the "source object so"
//The destructor does not free the memory multiple times.< C9/>other._data = nullptr;
other._length = 0;
Returns a reference to the current object, as shown in the following example:
The following example shows the complete move constructor and the move assignment operator for the Memoryblock class:
Move constructor. Memoryblock (memoryblock&&): _data (nullptr), _length (0) {std::cout << "in Memoryblock (Memoryblock &&). Length = "<< other._length <<".
Moving resource. "<< Std::endl;
Copy the data pointer and its length from the//source object.
_data = Other._data;
_length = Other._length;
The release of the data pointer from the "source object so"///The destructor does the memory multiple times.
Other._data = nullptr;
other._length = 0;
}//Move assignment operator. memoryblock& operator= (memoryblock&& other) {std::cout << ' in operator= (memoryblock&&).
Length = "<< other._length <<". "<< Std::endl;
if (this!= &other) {//Free the existing resource.
Delete[] _data;
Copy the data pointer and its length from the//source object.
_data = Other._data;
_length = Other._length; Release of the data pointer from the sourceObject so this//the destructor does the memory multiple times.
Other._data = nullptr;
other._length = 0;
return *this;
}
The following example demonstrates how mobile semantics can improve the performance of an application. This example adds two elements to a vector object and then inserts a new element between two existing elements. In Visual C + + 2010, the vector class uses mobile semantics to efficiently perform insertions by moving vector elements rather than copying them.
Rvalue-references-move-semantics.cpp
//compile with:/EHsc
#include "MemoryBlock.h"
#include < Vector>
using namespace std;
int main ()
{
//Create a vector object and add a few elements to it.
Vector<memoryblock> v;
V.push_back (memoryblock);
V.push_back (memoryblock);
Insert a new element into the second position of the vector.
V.insert (V.begin () + 1, memoryblock);
}
The example produces the following output:
in Memoryblock (size_t). length = 25. In Memoryblock (memoryblock&&). Length = 25.
Moving resource. In ~memoryblock ().
Length = 0. In Memoryblock (size_t).
Length = 75. In Memoryblock (memoryblock&&). Length = 25.
Moving resource. In ~memoryblock ().
Length = 0. In Memoryblock (memoryblock&&). Length = 75.
Moving resource. In ~memoryblock ().
Length = 0. In Memoryblock (size_t).
Length = 50. In Memoryblock (memoryblock&&). Length = 50.
Moving resource. In Memoryblock (memoryblock&&). Length = 50.
Moving resource. In Operator= (memoryblock&&).
Length = 75. In Operator= (memoryblock&&).
Length = 50. In ~memoryblock ().
Length = 0. In ~memoryblock ().
Length = 0. In ~memoryblock (). Length = 25.
deleting resource. In ~memoryblock (). Length = 50.
deleting resource. In ~memoryblock (). Length = 75.
deleting resource.
This sample version using mobile semantics is more efficient than a version that does not use mobile semantics, because the former performs fewer replication, memory allocations, and memory-release operations.
Reliable Programming
to prevent resource leaks, always release resources (such as memory, file handles, and sockets) in the move assignment operator.
To prevent unrecoverable resource corruption, correctly handle the self assignment in the move assignment operator.
If you provide both a move constructor and a move assignment operator for your class, you can write a move constructor to invoke the move assignment operator to eliminate redundant code. The following example shows the modified version of the move constructor that invokes the move assignment operator:
Move constructor.
Memoryblock (memoryblock&&)
: _data (nullptr)
, _length (0)
{
*this = Std::move (other);
}