C++ 使用右值引用和简单工厂
我最近了解了std::move和rvalue引用,并想知道我对它们的使用是否既适当又有效 考虑这个简单的图像类,它只存储一个表示像素的无符号字符值数组。请注意,实际上有比单个字符数组更多的成员,但为了可读性,我在这里进行了简化C++ 使用右值引用和简单工厂,c++,factory-method,C++,Factory Method,我最近了解了std::move和rvalue引用,并想知道我对它们的使用是否既适当又有效 考虑这个简单的图像类,它只存储一个表示像素的无符号字符值数组。请注意,实际上有比单个字符数组更多的成员,但为了可读性,我在这里进行了简化 using PixelContainer = std::vector<unsigned char>; class Image { public: Image(PixelContainer&& pixels) : m_pixels(st
using PixelContainer = std::vector<unsigned char>;
class Image {
public:
Image(PixelContainer&& pixels) : m_pixels(std::move(pixels)) {};
Image& operator=(Image&& image) { m_pixels = std::move(image.m_pixels); return *this; };
private:
PixelContainer m_pixels;
};
最后,它们一起用于代码中:
Image image = ImageFactory::loadImage("image.png");
我使用右值引用大概是为了省去制作可能是大量像素值的拷贝所花费的时间。由于工厂创建的矢量和图像是临时的,因此可以将它们四处移动
我的问题是,我的实现有意义吗?如果它没有根本性的缺陷,可以进一步改进吗?让我们来看看!我添加了这样一个函数来包含您的最后一段代码:
Image outer() {
Image image = ImageFactory::loadImage("image.png");
return image;
}
我还必须为我使用的Image=default添加一个常规的复制构造函数来定义它,因为即使它没有实际使用,也需要按值返回
然后我用铿锵-O2-g-S编译,并查看程序集。它主要是初始化向量的代码:调用操作符new并设置向量的内部指针。没有复制,代码看起来相当干净高效。正如您所希望的,outer的代码与loadImage的代码几乎相同,后者被内联到前者中,因为我将所有内容都放在一个翻译单元中
作为参考,以下是我得到的装配图:
outer(): ## @_Z5outerv
pushq %rbp
movq %rsp, %rbp
pushq %rbx
pushq %rax
movq %rdi, %rbx
movl $100000000, %edi ## imm = 0x5F5E100
callq operator new(unsigned long)
movd %rax, %xmm0
movlhps %xmm0, %xmm0 ## xmm0 = xmm0[0,0]
movq $-100000000, %rcx ## imm = 0xFFFFFFFFFA0A1F00
movq %rax, %rsi
LBB1_1: ## =>This Inner Loop Header: Depth=1
testq %rsi, %rsi
movl $0, %edx
je LBB1_3
movb $0, (%rsi)
movaps %xmm0, %xmm1
punpckhqdq %xmm1, %xmm1 ## xmm1 = xmm1[1,1]
movd %xmm1, %rdx
LBB1_3: ## %_ZNSt3__116allocator_traits...
incq %rdx
movd %rdx, %xmm1
punpcklqdq %xmm1, %xmm0 ## xmm0 = xmm0[0],xmm1[0]
incq %rcx
movq %rdx, %rsi
jne LBB1_1
## BB#4: ## %_ZN12ImageFactory9loadImageEPKc.exit
leaq 100000000(%rax), %rax
movdqu %xmm0, (%rbx)
movq %rax, 16(%rbx)
movq %rbx, %rax
addq $8, %rsp
popq %rbx
popq %rbp
retq
对不起,我必须投票才能结束。我个人认为你做得对。但是如果你问的是SO而不是codereview,你会得到更好的回答;当然,我只是想得到一个好的答案。一般规则是同时定义复制/移动构造函数和赋值运算符。除此之外,我没有看到任何明显的问题。我猜你们类的用户希望没有真正的复制构造函数,不是吗?@user3159253这是正确的。
outer(): ## @_Z5outerv
pushq %rbp
movq %rsp, %rbp
pushq %rbx
pushq %rax
movq %rdi, %rbx
movl $100000000, %edi ## imm = 0x5F5E100
callq operator new(unsigned long)
movd %rax, %xmm0
movlhps %xmm0, %xmm0 ## xmm0 = xmm0[0,0]
movq $-100000000, %rcx ## imm = 0xFFFFFFFFFA0A1F00
movq %rax, %rsi
LBB1_1: ## =>This Inner Loop Header: Depth=1
testq %rsi, %rsi
movl $0, %edx
je LBB1_3
movb $0, (%rsi)
movaps %xmm0, %xmm1
punpckhqdq %xmm1, %xmm1 ## xmm1 = xmm1[1,1]
movd %xmm1, %rdx
LBB1_3: ## %_ZNSt3__116allocator_traits...
incq %rdx
movd %rdx, %xmm1
punpcklqdq %xmm1, %xmm0 ## xmm0 = xmm0[0],xmm1[0]
incq %rcx
movq %rdx, %rsi
jne LBB1_1
## BB#4: ## %_ZN12ImageFactory9loadImageEPKc.exit
leaq 100000000(%rax), %rax
movdqu %xmm0, (%rbx)
movq %rax, 16(%rbx)
movq %rbx, %rax
addq $8, %rsp
popq %rbx
popq %rbp
retq