Конструктор перемещения и назначение перемещения

Я читал книгу Бьярна Страуструпа (создатель C++) "4-й выпуск языка программирования C++" и изучал конструкторы и назначения перемещений.

В книге для вектора класса (см. 1 для заголовка ниже) он показывает, как реализовать конструктор перемещения (см. 2 ниже), и говорит, что назначение перемещения реализовано аналогичным образом, но не показывает, как. Я сам выполнил назначение перемещения (см. 3 ниже), и все, кажется, работает нормально, однако я не уверен, что выполнил это правильно.

Я не получаю никаких ошибок и посмотрел на многих примерах, но я не могу подтвердить его правильность для моего конкретного класса. Может кто-то имел опыт работы с C++, пожалуйста, посмотрите на мой код и прокомментируйте, если он правильный?

РЕДАКТИРОВАТЬ: Также см. 4 для конструкторов и деструкторов.

Спасибо за ваше время.

PS: любые полезные советы или модификации приветствуются

1) Заголовочный файл класса:

#ifndef VECTOR_H
#define VECTOR_H

#include <cstdlib>
#include <iostream>
#include <stdexcept>

using namespace std;

template<typename T>
class Vector {

public:
    // constructors
    Vector(int s);
    Vector(std::initializer_list<T>);

    // destructor
    ~Vector();

    // copy constructor and copy assignment
    Vector(Vector&);
    Vector<T>& operator=(Vector&);

    // move constructor and move assignment
    Vector(Vector&&);
    Vector<T>& operator=(Vector&&);

    // operators
    T& operator[](int);
    const T& operator[](int) const; // the second const means that this function cannot change the state of the class
                                    // we define operator[] the second time for vectors containing constant members;
    // accessors
    int getSize();


private:
    int size;
    T* elements;

};

#endif /* VECTOR_H */

2) Переместить конструктор (реализован так же, как и книга):

// move constructor 
template<typename T>
Vector<T>::Vector(Vector&& moveme) : size{moveme.size}, elements{moveme.elements}
{
    moveme.elements = nullptr;
    moveme.size = 0;
}

3) Переместить задание (не уверен, правильно ли):

// move assignment
template<typename T>
Vector<T>& Vector<T>::operator=(Vector&& moveme) 
{
    delete[] elements; // delete old values
    elements = moveme.elements;
    size = moveme.size;
    moveme.elements = nullptr;
    moveme.size = 0;
    return *this;
}

4) Конструкторы и деструкторы:

#include <array>

#include "Vector.h"

// constructors
template<typename T>
Vector<T>::Vector(int s) {    
    if(s<0) throw length_error{"Vector::Vector(int s)"};
    // TODO: use Negative_size{} after learning how to write custom exceptions
    this->size = s;
    this->elements = new T[s];
}

template<typename T>
Vector<T>::Vector(std::initializer_list<T> list) : size(list.size()), 
        elements(new T[list.size()]) 
{
    copy(list.begin(), list.end(), elements);
}

// destructor
template<typename T>
Vector<T>::~Vector()
{
    delete[] this->elements;
}

1 ответ

Решение

Поскольку на этот вопрос ответили в комментариях, я подумал, что последую совету мета: Вопрос без ответов, но проблема решена в комментариях (или расширена в чате), и напишу короткую вики-страницу сообщества, чтобы закрыть и ответить на вопрос.

Я также добавлю полезную дополнительную информацию и советы от других пользователей, которые присоединились к обсуждению в комментариях.

Bo Persson ответил и предоставил дополнительную информацию о размещении шаблона:

Назначение перемещения кажется разумным, за исключением того, что размещение шаблонов в файле cpp позволяет использовать их только в этом файле cpp. См. Почему шаблоны могут быть реализованы только в заголовочном файле?

Rakete1111 разъясняет Rakete1111 заблуждение относительно семантики перемещения:

std:: move! = семантика перемещения У вас есть семантика перемещения, в которой можно переместить значения (используя конструктор перемещения) вместо копирования. std::move - это просто средство, позволяющее включить семантику перемещения (например, с помощью конструктора перемещения) для типов, которые не являются значениями.

Post Self поднимает вопрос оптимизации возврата с Post Self, и я отвечаю:

... Кроме того, действительно ли нет никакой оптимизации возвращаемого значения, если у вас нет перегруженных каторов / назначений перемещения? -kim366

Кажется, что в примере (см. Функцию ниже) он говорит, что z = x + y + z дважды скопирует возвращаемый результат: "Если вектор большой, скажем, 10000 удваивается, это может быть неловко". Но "Учитывая это определение, компилятор выберет конструктор перемещения для реализации переноса возвращаемого значения..." Он изобрел C++, так что я просто не пойму его слова:). Vector operator+(const Vector& a, const Vector& b) { if (a.size()!=b.size()) throw Vector_size_mismatch{}; Vector res(a.size()); for (int i=0; i!=a.size(); ++i) res[i]=a[i]+b[i]; return res; } - хаммерамр

(Пример был взят из книги Бьярна Страуструпа "Язык программирования C++, 4-е издание")

Смотрите также Что такое иероглиф копирования и обмена? Джайв Дадсон

Надеюсь, что люди найдут это полезным и спасибо за тех, кто принял участие.

Другие вопросы по тегам