是否可以在 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<...>(CGAL::Kd_tree&)
或类似的
@463035818_is_not_a_number 你是对的,扩大我的缩写,是CGAL::Kd_tree<...>::Kd_tree(const Tree&) [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++ 中将返回值移动语义与受保护的复制构造函数一起使用?的主要内容,如果未能解决你的问题,请参考以下文章