c++ - 包含仅 move 类型的类的构造函数应该通过引用还是通过右值引用接收仅 move 类型?

标签 c++ move-semantics

最近开始学习 move 语义,这几天一直在思考以下问题:

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

class Texture
{
public:

   Texture(unsigned int texID);
   ~Texture();

   Texture(const Texture&) = delete;
   Texture& operator=(const Texture&) = delete;

   Texture(Texture&& rhs);
   Texture& operator=(Texture&& rhs);

   // ...

private:

   unsigned int mTexID;
};

对于那些想知道的人,在使用 OpenGL 时通常会有这样的包装类。 ID 用于访问存储在 GPU 中的数据,并用于告诉 GPU 销毁所述数据,这是在该包装类的析构函数中完成的。这就是为什么它是一个不可复制的类。

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

class Mesh
{
public:

   // Notice how the constructor receives the vector of Texture objects (a move-only type) by reference
   Mesh(const std::vector<unsigned int>& indices, std::vector<Texture>& textures)
      : mIndices(indices)
      , mTextures(std::move(textures))
   {
      // ...
   }
   ~Mesh();

   Mesh(const Mesh&) = delete;
   Mesh& operator=(const Mesh&) = delete;

   Mesh(Mesh&& rhs);
   Mesh& operator=(Mesh&& rhs);

   // ...

private:

   std::vector<unsigned int> mIndices;
   std::vector<Texture>      mTextures;
};

使用现在的构造函数,客户端可以通过执行以下操作来创建 Mesh:

std::vector<unsigned int> indices;
std::vector<Texture> textures;

// ...

Mesh mesh(indices, textures); // Client is unaware that the textures vector has been moved from

我的问题是,如果 Mesh 类的构造函数声明如下是否会更好:

// Notice how the constructor receives the vector of Texture objects (a move-only type) by rvalue reference
Mesh::Mesh(const std::vector<unsigned int>& indices, std::vector<Texture>&& textures)
   : mIndices(indices)
   , mTextures(std::move(textures))
{
   // ...
}

使用这个新构造函数,客户端在创建 Mesh 对象时将被迫执行以下操作:

std::vector<unsigned int> indices;
std::vector<Texture> textures;

// ...

Mesh mesh(indices, std::move(textures)); // Client is fully aware that the textures vector has been moved from

这肯定需要更多的输入,但现在用户完全意识到纹理 vector 已被移走,而且我没有看到任何性能影响。

所以我想我的问题是:是否有关于接收将从中 move 的仅 move 类型的最佳方式的指南?通过引用接收 const 显然表明类型不会被 move ,那么如何做相反的事情呢?如何告诉客户该类型将被移出?

最佳答案

如果传递的值可能是纯右值,则使用右值引用显然更优越:

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

关于c++ - 包含仅 move 类型的类的构造函数应该通过引用还是通过右值引用接收仅 move 类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56727467/

相关文章:

c++ - 前进或 move

c++ - 使用 boost 的文件行数

c++ - 查找 3D 坐标是否已被使用的最快方法

c++ - 我在使用 cuSolver 的设备上找不到 LU 分解

c++ - move 语义 std::move 如何使用它

c++ - 不必要清空移出的 std::string

c++ - 空的用户定义的 move 构造函数

c++ - move : what does it take?

c++ - 在 C++ 中打印数组的元素,以及变量的内部与外部初始化

c++ - 将非静态数据成员作为默认参数传递给方法