我最近在 SE 上发布了一个关于下面代码的问题,因为它产生了编译错误。有人很友好地回答说,当您实现移动构造函数或移动赋值运算符时,会删除默认的复制构造函数。他们还建议,然后我需要使用std::move()
来获得这样的工作:
Image src(200, 200);
Image cpy = std::move(src);
现在这对我来说是有意义的,因为在这种情况下您想要使用移动赋值运算符或移动构造函数的事实必须明确。src
在这个例子中是一个左值,cpy
除非你用std::move
. 但是,我对这段代码有更多的问题:
Image cpy = src + src
我没有把副本放在operator +
下面,但它是一个简单的类型的重载运算符:
Image operator + (const Image &img) const {
Image tmp(std::min(w, img.w), std::min(h, img.h));
for (int j = 0; j < tmp.h; ++j) {
for (int i = 0; i < tmp.w; ++i) {
// accumulate the result of the two images
}
}
return tmp;
}
在这种特殊情况下,我假设运算符以 的形式返回一个临时变量,tmp
并且在这种情况下,当您到达 时,将触发移动赋值运算符cpy = src + src
。我不确定说 的结果src + src
是左值是否准确,因为实际上返回的是tmp
,但随后tmp
被复制/分配给cpy
. 因此,在移动运算符存在之前,这将触发默认的复制构造函数。但是为什么在这种情况下不使用移动构造函数呢?看来我还需要做一个:
Image cpy = std::move(src + src);
为了让它工作,我假设它为operator +
类 Image 返回的变量获取一个 xvalue?
有人可以帮助我更好地理解这一点吗?告诉我哪里不对?
谢谢你。
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <fstream>
#include <cassert>
class Image
{
public:
Image() : w(512), h(512), d(NULL)
{
//printf("constructor default\n");
d = new float[w * h * 3];
memset(d, 0x0, sizeof(float) * w * h * 3);
}
Image(const unsigned int &_w, const unsigned int &_h) : w(_w), h(_h), d(NULL)
{
d = new float[w * h * 3];
memset(d, 0x0, sizeof(float) * w * h * 3);
}
// move constructor
Image(Image &&img) : w(0), h(0), d(NULL)
{
w = img.w;
h = img.h;
d = img.d;
img.d = NULL;
img.w = img.h = 0;
}
// move assignment operator
Image& operator = (Image &&img)
{
if (this != &img) {
if (d != NULL) delete [] d;
w = img.w, h = img.h;
d = img.d;
img.d = NULL;
img.w = img.h = 0;
}
return *this;
}
//~Image() { if (d != NULL) delete [] d; }
unsigned int w, h;
float *d;
};
int main(int argc, char **argv)
{
Image sample;// = readPPM("./lean.ppm");
Image res = sample;
return 0;
}