C++ 包含仅移动类型的类的构造函数是否应通过引用或右值引用接收仅移动类型?

C++ 包含仅移动类型的类的构造函数是否应通过引用或右值引用接收仅移动类型?,c++,move-semantics,C++,Move Semantics,我最近开始学习移动语义,几天来我一直在思考以下问题: 假设我们有一个不可复制的类,如下所示: 类纹理 { 公众: 纹理(无符号int-texID); ~Texture(); 纹理(常量纹理&)=删除; 纹理和运算符=(常量纹理&)=删除; 纹理(纹理和rhs); 纹理和运算符=(纹理和rhs); // ... 私人: 无符号int-mTexID; }; 对于那些想知道的人来说,在使用OpenGL时有这样的包装器类是很常见的。ID用于访问存储在GPU中的数据,并告诉GPU销毁所述数据,这是在该包

我最近开始学习移动语义,几天来我一直在思考以下问题:

假设我们有一个不可复制的类,如下所示:

类纹理
{
公众:
纹理(无符号int-texID);
~Texture();
纹理(常量纹理&)=删除;
纹理和运算符=(常量纹理&)=删除;
纹理(纹理和rhs);
纹理和运算符=(纹理和rhs);
// ...
私人:
无符号int-mTexID;
};
对于那些想知道的人来说,在使用OpenGL时有这样的包装器类是很常见的。ID用于访问存储在GPU中的数据,并告诉GPU销毁所述数据,这是在该包装类的析构函数中完成的。这就是为什么它是一个不可复制的类

现在假设我们有另一个不可复制的类,如下所示:

类网格
{
公众:
//请注意构造函数如何通过引用接收纹理对象的向量(仅移动类型)
网格(常量标准::向量和索引,标准::向量和纹理)
:mIndices(索引)
,mtexture(std::move(纹理))
{
// ...
}
~Mesh();
网格(常数网格&)=删除;
网格和运算符=(常量网格-)=删除;
网格(网格和rhs);
网格和运算符=(网格和rhs);
// ...
私人:
病媒思维;
std::向量mtexture;
};
使用当前的构造函数,客户端可以通过执行以下操作来创建
网格

std::向量索引;
矢量纹理;
// ...
网格(索引、纹理);//客户端不知道纹理向量已从中移动
我的问题是如果
Mesh
类的构造函数声明如下是否会更好:

//注意构造函数如何通过右值引用接收纹理对象的向量(仅移动类型)
网格::网格(常数std::向量和索引,std::向量和纹理)
:mIndices(索引)
,mtexture(std::move(纹理))
{
// ...
}
使用此新构造函数,客户端在创建
Mesh
对象时将被迫执行以下操作:

std::向量索引;
矢量纹理;
// ...
网格(索引,标准::移动(纹理));//客户端完全知道纹理向量已从
当然,它需要更多的输入,但现在用户完全知道纹理向量已经从中移出,我看不到任何性能影响


所以我想我的问题是:是否有关于接收将从中移动的仅移动类型的最佳方式的指导方针?通过引用const进行接收清楚地表明类型不会从中移动,那么如何做相反的事情呢?如何告诉客户端类型将从中移动?

如果传递的值可能是prvalue,则使用右值引用显然优于:

struct A {};
struct B {B(A&);};
struct C {C(A&&);};
A get();
A a;

B b{a};              // OK: a is an lvalue
B b2{get()};         // error: prvalue
C c{a};              // error: lvalue
C c2{std::move(a)};  // OK: xvalue
C c3{get()};         // OK: prvalue

这主要是个人的选择。非常量左值引用意味着允许修改正在传递的对象。非常量值引用意味着有权移动正在传递的对象。在这种情况下,最终结果是相同的。但是,由于所讨论的构造函数正在执行移动,因此右值引用对于自行记录代码实际执行的操作更有意义。@Nikos C但包含仅移动类型(如纹理)的向量是仅移动类型,对吗?@RemyLebeau我希望能接受您的评论作为此问题的答案!您是对的,这是一个个人选择,我同意右值引用对代码进行自我文档化更有意义。谢谢你的意见!请注意,您应该将move构造函数和move赋值声明为
noexcept
,以便使该类型的向量可用。(插入到向量中可能需要移动所有对象,如果移动过程可能抛出,这是不安全的)我想你基本上回答了你自己的问题,顺便说一句。我没有想到这个限制!谢谢你指出这一点。