Перемещение присваивания при суммировании перегруженных векторов - PullRequest
1 голос
/ 18 июня 2020

Я просматриваю Знакомство с C ++ (Раздел 5.2 Копирование и перемещение). Следуя инструкциям в книге, я построил контейнер под названием Vector (он имитирует std::vector). Моя цель - эффективно реализовать следующее (поэлементное) суммирование:

Vector r = x + y + z;

Согласно книге, если у меня нет присваивания перемещения и конструктора, оператор + в конечном итоге скопирует Vector s без надобности. Итак, я реализовал назначение перемещения и конструктор, но я думаю, что компилятор все еще не использует их, когда я запускаю Vector r = x + y + z;. Что мне не хватает? Я ценю любую обратную связь. Ниже мой код. Я ожидаю увидеть результат Move assignment, но ничего не получаю. (Суммирующая часть работает, это просто переезд, в котором я не уверен)

Код

// Vector.h
class Vector{

public:
    explicit Vector(int);
    Vector(std::initializer_list<double>);
    // copy constructor
    Vector(const Vector&);
    // copy assignment
    Vector& operator=(const Vector&);
    // move constructor
    Vector(Vector&&);
    // move assignment
    Vector& operator=(Vector&&);
    ~Vector(){delete[] elem;}
    double& operator[](int) const;
    int size() const;
    void show();
    friend std::ostream& operator<< (std::ostream& out, const Vector& vec);

private:
    int sz;
    double* elem;
};

Vector operator+(const Vector&,const Vector&);

// Vector.cpp

Vector::Vector(std::initializer_list<double> nums) {
    sz = nums.size();
    elem = new double[sz];
    std::initializer_list<double>::iterator it;
    int i = 0;
    for (it=nums.begin(); it!=nums.end(); ++it){
        elem[i] = *it;
        ++i;
    }
}

Vector::Vector(Vector&& vec) {
    sz = vec.sz;
    vec.sz = 0;
    elem = vec.elem;
    vec.elem = nullptr;
    std::cout<<"Move constructor"<<std::endl;
}

Vector& Vector::operator=(Vector&& vec) {
    if (this == &vec){
        return *this;
    }
    sz = vec.sz;
    vec.sz = 0;
    elem = vec.elem;
    vec.elem = nullptr;
    std::cout<<"Move assignment"<<std::endl;
    return *this;

Vector operator+(const Vector& vec1, const Vector& vec2){
    if (vec1.size() != vec2.size()){
        throw std::length_error("Input vectors should be of the same size");
    }
    Vector result(vec1.size());
    for (int i=0; i!=vec1.size(); ++i){
        result[i] = vec1[i]+vec2[i];
    }
    return result;
}
}
// Main
int main() {
    Vector x{1,1,1,1,1};
    Vector y{2,2,2,2,2};
    Vector z{3,3,3,3,3};
    Vector r = x + y + z;
} // Here I expect the output: Move assignment, but I get no output.

1 Ответ

2 голосов
/ 18 июня 2020

Происходит исключение перемещения.

Согласно стандарту C ++ 17 (12.8 Копирование и перемещение объектов класса)

31 При соблюдении определенных критериев реализации разрешается опускать конструкцию копирования / перемещения объекта класса, даже если конструктор, выбранный для операции копирования / перемещения, и / или деструктор для объекта имеют побочные эффекты. В таких случаях реализация обрабатывает источник и цель пропущенной операции копирования / перемещения как просто два разных способа ссылки на один и тот же объект, и уничтожение этого объекта происходит в более позднее время, когда два объекта были бы уничтожены без оптимизации.122 Это исключение операций копирования / перемещения, называемых копированием, разрешается в следующих случаях (которые могут быть объединены для исключения нескольких копий):

(31.3) - когда временный объект класса, который не был привязан к ссылке (12.2) будет скопирован / перемещен в объект класса с того же типа cv-unqualified, операция копирования / перемещения может быть опущена путем создания временного объекта непосредственно в цель пропущенного копирования / перемещения

Таким образом, конструктор перемещения опущен. Второй временный объект, созданный выражением x + y + z;, строится напрямую как объект r.

Vector r = x + y + z;

Также учтите, что в операторе возврата оператора

есть исключение перемещения.

(31.1) - в операторе возврата в функции с типом возвращаемого класса, когда выражение является именем энергонезависимого автоматического объекта c (кроме функции или параметра catch-clause) с тем же cvunqualified в качестве типа возвращаемого значения функции, операцию копирования / перемещения можно опустить, сконструировав объект automati c непосредственно в возвращаемое значение функции

Таким образом, временный объект создается в выражении x + y (внутри оператора) будет перемещен (то есть будет исключение относительно оператора return - предшествующей кавычки) в выражении ( x + y ) + z, где он будет использоваться постоянной ссылкой lvalue, а новый временный объект, созданный в этом выражении, будет построен как r.

В целом в этом фрагменте кода

* 1 028 *

за счет исключения перемещения будет создано 5 объектов класса Vector.

...