You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++中拷贝构造函数私有/受保护的类能否使用返回值移动语义?

背后原理

这个问题是C03到C11的语法兼容性,以及移动构造的隐式生成规则共同导致的:

  • 旧版C++规范里禁止类型拷贝的常规做法是把拷贝构造函数声明为private且不实现,你用到的CGAL Kd_tree用的就是这种写法。
  • 按照C++标准,只要类自定义了拷贝构造函数(无论访问权限是什么),编译器都不会自动生成默认的移动构造函数和移动赋值运算符。
  • 你返回局部对象tree时,编译器首先会尝试匹配移动构造,找不到移动构造就会回退到拷贝构造,而拷贝构造是私有成员,自然会触发编译报错。
  • 哪怕实际编译时会触发*RVO(返回值优化)*省略掉拷贝/移动操作,语法层面仍然要求对应的构造函数是可访问的,所以哪怕优化后不需要调用,也过不了编译检查。

你当前可以使用的解决方法

  • 方案1:用智能指针包装返回值,完全规避PointTree本身的拷贝/移动需求
#include <memory>

std::unique_ptr<PointTree> preparePointTree(const vector<PlyPoint>& pointCloud) {
  auto tree = std::make_unique<PointTree>();
  kd_tree::prepare<...>(pointCloud, *tree);
  return tree;
}

// 调用方式
auto tree = preparePointTree(pointCloud);
  • 方案2:改用输出参数传递结果,写法虽然不够简洁但兼容性最高
void preparePointTree(const vector<PlyPoint>& pointCloud, PointTree& out_tree) {
  kd_tree::prepare<...>(pointCloud, out_tree);
}

// 调用方式
PointTree tree;
preparePointTree(pointCloud, tree);
  • 方案3:如果你可以修改本地CGAL头文件,可以直接给Kd_tree添加public的移动构造,之后就可以按你原来的写法返回对象。

CGAL库侧的适配方案

CGAL只需要把原有禁止拷贝的写法,替换为C++11之后的标准写法,就可以同时实现禁止拷贝、支持移动的需求:

public:
  // 显式声明移动操作为默认实现,允许移动
  Kd_tree(Kd_tree&&) = default;
  Kd_tree& operator=(Kd_tree&&) = default;
  // 显式删除拷贝操作,禁止拷贝
  Kd_tree(const Kd_tree&) = delete;
  Kd_tree& operator=(const Kd_tree&) = delete;

替换原有private拷贝构造的写法后,用户侧的返回值写法就可以正常编译,不需要额外修改。

内容的提问来源于stack exchange,提问作者nh2

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 20:24:03