#include
using namespace std;
2 :
class MyString
{
private:
char* Buffer;
// закрытый стандартный конструктор
MyString(): Buffer(NULL)
1 0 :
|
{
|
11:
|
cout « "Default constructor called" « endl;
|
1 2 :
|
}
|
13:
|
|
public:
// Деструктор
~MyString()
332 ЗАНЯТИЕ 12. Типы операторов и их перегрузка
17:
if (Buffer != NULL)
delete [] Buffer;
2 0 :
|
}
|
2 1 :
|
int GetLengthO
|
2 2 :
|
{
return strlen(Buffer);
25:}
operator const char*()
{
return Buffer;
30:
31:
MyString operator* (const MyStringS AddThis)
{
cout « ’’operator* called: " « endl;
MyString NewString;
36:
|
if (AddThis.Buffer
|
NULL)
|
37:
|
{
NewString.Buffer = new char[GetLength() \
strlen(AddThis.Buffer) + 1];
strcpy(NewString.Buffer, Buffer);
strcat(NewString.Buffer, AddThis.Buffer);
return NewString;
}
46:
// Конструктор
MyString(const char* Initiallnput)
{
cout « "Constructor called for: " « Initiallnput « endl;
if(Initiallnput != NULL)
{
Buffer = new char [strlen(Initiallnput) + 1];
strcpy(Buffer, Initiallnput);
}
else
Buffer = NULL;
}
59:
// конструктор копий
MyString(const MyString& CopySource)
{
cout«"Copy constructor to copy from: " « CopySource.Buffer
endl;
if(CopySource.Buffer != NULL)
{
66:
|
//
|
гарантировать
|
глубокое копирование, зарезервировав
|
|
//
|
предварительно
|
собственный буфер
|
6 7 :
|
Buffer = new char
|
[strlen(CopySource.Buffer) + 1];
|
6 8:
// копировать из оригинала в локальный буфер
strcpy(Buffer, CopySource.Buffer);
71:
else
Buffer = NULL;
}
75:
// Оператор присвоения копии
MyString& operator= (const MyString& CopySource)
{
cout«"Copy assignment operator to copy from: " « CopySource.Buffer « endl;
if ((this != &CopySource) && (CopySource.Buffer != NULL))
{
if (Buffer != NULL)
// гарантировать глубокое копирование, зарезервировав
// предварительно собственный буфер
86: Buffer = new char [strlen(CopySource.Buffer) + 1];
87:
8 8 : // копировать из оригинала в локальный буфер
strcpy(Buffer, CopySource.Buffer);
return *this;
}
94:
// Конструктор перемещения
MyString(MyString&& MoveSource)
{
cout « "Move constructor to move from: "
MoveSource.Buffer « endl;
if(MoveSource.Buffer != NULL)
100:
|
{
|
// взять собственность
|
101:
|
Buffer = MoveSource.Buffer;
|
|
MoveSource.Buffer = NULL;
|
// т .e . 'переместить'
|
102:
|
//
|
освободить источник
|
|
|
//
|
перемещения
|
}
}
105:
// Оператор присваивания при перемещении
MyStringS operator= (MyString&& MoveSource)
{
cout«"Move assignment operator to move from: "
MoveSource.Buffer « endl;
110:
|
if((MoveSource.Buffer != NULL) &&
|
(this != &MoveSource))
|
111:
|
{
|
собственный буфер
|
112:
|
delete Buffer; // освободить
|
113:
|
|
|
Buffer = MoveSource.Buffer; // взять собственность
т .e . 'переместить'
ЗАНЯТИЕ 12. Типы операторов и их перегрузка
MoveSource.Buffer = NULL; // освободить источник
перемещения
116
117
return *this;
20: };
121
122 int main ()
123: {
MyString Hello("Hello ");
MyString World("World");
MyString CPP(" of C++");
MyString sayHelloAgain ("overwrite this");
sayHelloAgain = Hello + World + CPP;
Результат
Вывод без конструктора перемещ ения и оператора присваивания при перемещении (при закомментированных строках 95-119):
Constructor called for: Hello
Constructor called for: World
Constructor called for: of C++
Constructor called for: overwrite this
operator+ called:
Default constructor called
Copy constructor to copy from: Hello World operator+ called:
Default constructor called
Copy constructor to copy from: Hello World of C++
Copy assignment operator to copy from: Hello World of C++
Вывод с конструктором перемещения и оператором присваивания при перемещении:
Constructor called for: Hello
Constructor called for: World
Constructor called for: of C++
Constructor called for: overwrite this
operator+ called:
Default constructor called
Move constructor to move from: Hello World operator+ called:
Default constructor called
Move constructor to move from: Hello World of C++
Move assignment operator to move from: Hello World of C++
Операторы, которые не могут быть перегружены
|
335
|
Анализ
Пример кода получился действительно длинным, но большая его часть уже была пред ставлена в предыдущих примерах и занятиях. Самая важная часть этого листинга находит ся в строках 95-119, где реализованы конструктор перемещения и оператор присваивания при перемещении соответственно. Те части вывода, на которые воздействуют нововведе ния стандарта С++11, выделены полужирным шрифтом. Обратите внимание, насколько существенно изменился вывод по сравнению с тем же классом, но без этих двух средств. Если рассмотреть реализацию конструктора перемещения и оператора присваивания при перемещении, то можно заметить, что семантика перемещения по существу реализуется за счет принятия принадлежности ресурсов от источника перемещения (строка 101 в кон структоре перемещения и строка 114 в операторе присваивания при перемещении). Непо средственно за этим следует присвоение значения NULL указателю источника (строки 102
115). Таким образом, даже когда источник перемещения удаляется, вызываемый через деструктор в оператор d e l e t e (строки 16-20) по существу ничего не делает, поскольку собственность была передана объекту получателя. Обратите внимание, что в отсутствии конструктора перемещения вызывается конструктор копий, который осуществляет глубо кое копирование строки. Таким образом, конструктор перемещения существенно эконо мит на продолжительности обработки и сокращает количество нежелательных операций резервирования памяти и этапов копирования.
Создание конструктора перемещения и оператора присваивания при перемещении со вершенно необязательно. В отличие от конструктора копий и оператора присвоения копии, компилятор не добавляет его стандартную реализацию сам.
Используйте эти средства С++11 для оптимизации работы классов, которые указывают на динамически распределяемые ресурсы, которые в противном случае требовали бы глу бокого копирования даже в тех случаях, где они требуются только временно.
Do'stlaringiz bilan baham: |