是否可以在 C++ 中将返回值移动语义与受保护的复制构造函数一起使用?

Posted

技术标签:

【中文标题】是否可以在 C++ 中将返回值移动语义与受保护的复制构造函数一起使用?【英文标题】:Is it possible to use return value move semantics with a protected copy constructor in C++? 【发布时间】:2021-11-10 22:10:30 【问题描述】:

我正在使用CGAL 库并编写一个我希望使用移动语义as described in this question 的函数:

PointTree preparePointTree(const vector<PlyPoint>& pointCloud) 
  PointTree tree;
  kd_tree::prepare<...>(pointCloud, tree);
  return tree;

我这样称呼它:

PointTree tree = preparePointTree(pointCloud);

不幸的是,它无法编译; GCC 抱怨:

return tree;  // <-- error: 'CGAL::Kd_tree<...>' is private within this context

附注:

private:
  // protected copy constructor
  Kd_tree(const Tree& tree)   // <-- note: declared private here

来自this code。

所以问题似乎是,如果复制构造函数不可用,则返回 tree 是非法的,即使我不想复制而是移动。

我想这是因为移动语义依赖于调用站点(对preparePointTree()的调用),并且函数实现本身被视为“即使在非移动情况下也必须编译”。

那么,现在呢?

我或 CGAL 库可以做些什么来允许移动但不能复制?

这背后的原因是什么?

【问题讨论】:

你能否将返回值作为第二个参数传入并进行显式移动? 但是kd_tree 根本不支持移动。通过unique_ptr 或其他方式包装它。 “即使我不想复制,但要移动” - 它确实会尝试移动。但是Kd_tree没有提供移动构造函数,并且它的自动生成被用户声明的复制c'tor禁止。这个类并不像看起来那样被传递。尝试间接。 我想实际的错误消息不会说“错误:'CGAL::Kd_tree<...>' 在此上下文中是私有的”,而是CGAL::Kd_tree&lt;...&gt;(CGAL::Kd_tree&amp;) 或类似的 @463035818_is_not_a_number 你是对的,扩大我的缩写,是CGAL::Kd_tree&lt;...&gt;::Kd_tree(const Tree&amp;) [with ...2000 more chars...] 【参考方案1】:

来自cppreference on move constructors:

如果没有为类类型(结构、类或联合)提供用户定义的移动构造函数,并且以下所有情况都为真:

没有用户声明的复制构造函数; 没有用户声明的复制赋值运算符; 没有用户声明的移动赋值运算符; 没有用户声明的析构函数。

然后编译器将使用签名 T::T(T&&) 将移动构造函数声明为其类的非显式内联公共成员。

Kd_tree 类提供了用户声明的复制构造函数,因此它不会自动获取移动构造函数。由于它没有移动构造函数,因此您无法移动它。

【讨论】:

你可以在没有移动工具的情况下“移动”东西。复制 c'tor 可以达到这个目的。但它必须是可访问的。 “移动”事物(引号)是什么意思? (N)RVO,完全省略了复制/移动? @Kevin 一个不能移动但可以复制的东西只是一个副本 提供返回本地的 return 语句是首先将其视为右值,然后(如果重载解析失败)将其视为左值。无论NRVO如何,这种情况总是会发生。复制 c'tor 的 const 引用可以绑定到一个右值,因此它会在没有生成 move c'tor 时使用。因此引用。它已成功移动,但通过复制。

以上是关于是否可以在 C++ 中将返回值移动语义与受保护的复制构造函数一起使用?的主要内容,如果未能解决你的问题,请参考以下文章

❥关于C++之右值引用&移动语义┇移动构造&移动复制

如何将 ACL 与受保护的资源连接起来?

c++ 移动语义及使用(续)

c++的左值(lvalue),右值(rvalue),移动语义(move),完美转发(forward)

右值引用,移动语义,完美转发

C++ 专题 右值引用移动语义与完美转发