【发布时间】:2020-06-17 22:04:26
【问题描述】:
我正在阅读 C++ 之旅(第 5.2 节复制和移动)。按照书中的说明,我构建了一个名为Vector 的容器(它模仿了std::vector)。我的目标是有效地实现以下(逐元素)求和:
Vector r = x + y + z;
根据本书,如果我没有移动赋值和构造函数,+ 运算符最终会不必要地复制Vectors。所以我实现了移动赋值和构造函数,但我认为当我运行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.
【问题讨论】:
-
您希望行的哪一部分执行移动assignment?您需要创建临时对象,因为
operator+和Vector r是从该临时对象构造的 -
您的移动赋值运算符泄漏内存。
-
@PaulMcKenzie 我看不到泄漏,你能解释一下吗?
-
elem = vec.elem;-- “老”元素怎么了?好像你没有delete []它。 -
一旦执行该行,您就丢失了
elem指向的原始地址。你怎么去delete[]那段记忆?你应该做的是std::swapelem值,这样传入的对象就可以销毁旧数据。对于移动分配,您希望交换数据而不是直接用nullptr替换它(如移动构造函数)。
标签: c++ class vector move-constructor copy-elision