在重载向量求和中移动赋值

Move assignment in overloaded vector summation

我正在复习 C++ 之旅(第 5.2 节复制和移动)。按照书中的说明,我构建了一个名为 Vector 的容器(它模仿 std::vector)。我的目标是有效地实现以下(按元素)求和:

Vector r = x + y + z;

根据这本书,如果我没有移动赋值和构造函数,+ 运算符最终将不必要地复制 Vector。所以我实现了移动赋值和构造函数,但我认为当我 运行 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.

发生了一步省略。

根据 C++ 17 标准(12.8 复制和移动 class 对象)

31 When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the constructor selected for the copy/move operation and/or the destructor for the object have side effects. In such cases, the implementation treats the source and target of the omitted copy/move operation as simply two different ways of referring to the same object, and the destruction of that object occurs at the later of the times when the two objects would have been destroyed without the optimization.122 This elision of copy/move operations, called copy elision, is permitted in the following circumstances (which may be combined to eliminate multiple copies):

(31.3) — when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move

所以省略了移动构造函数。表达式x + y + z;创建的第二个临时对象直接构建为对象r.

Vector r = x + y + z;

还要考虑到运算符return语句中有move elision

(31.1) — in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) with the same cvunqualified type as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function’s return value

因此在表达式 x + y 中创建的临时对象(在运算符内)将在表达式 ( x + y ) + z 它将被常量左值引用使用,并且在此表达式中创建的新临时对象将构建为 r.

全部在这个代码片段中

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;

由于移动省略,将创建 class 向量的 5 个对象。