【问题标题】:Return local value from function without triggering copy constructor从函数返回本地值而不触发复制构造函数
【发布时间】:2017-11-28 18:03:33
【问题描述】:

我正在尝试使用 c++ 类型系统删除复制构造函数以防止复制对象。

struct DeleteCopyConstructor {
    DeleteCopyConstructor() {};
    DeleteCopyConstructor(DeleteCopyConstructor& op2) = delete;
    DeleteCopyConstructor(const DeleteCopyConstructor& op2) = delete;
};

DeleteCopyConstructor f() {
    DeleteCopyConstructor d;
    // initialize d...
    return d;
}

错误是:

error: use of deleted function ‘DeleteCopyConstructor::DeleteCopyConstructor(const DeleteCopyConstructor&)’

我读过关于复制省略的内容,但它似乎是一种编译器优化,所以我认为它不适用。如何在不触发复制构造的情况下返回d

【问题讨论】:

  • 复制省略(称为返回值优化或 NRVO)将适用于这种情况。很可能你的编译器实现了它。
  • 要把它从桌面上移开吗?
  • 顺便说一句,您不需要delete 两个复制构造函数。
  • 是否删除了复制构造函数以防止危险/不合逻辑的复制?
  • 在 freenode IRC 上询问。如果我提供移动构造函数,代码就会编译。 DeleteCopyConstructor(DeleteCopyConstructor&& op2) = default;

标签: c++ class oop copy-constructor copy-elision


【解决方案1】:

在 C++17 中the compiler is guaranteed to elide the copy。但是在所有情况下,您仍然需要有一个有效的复制构造函数。

因此,如果您只关心性能,则无需执行任何操作。如果您想删除复制构造函数,因为该值在逻辑上不应该是可复制的,那么据我所知,没有办法做到这一点。您必须返回 std::unique_ptr<T> 或通过引用获取值并以这种方式进入。编辑:或者定义一个移动构造函数。

【讨论】:

  • std::unique_ptr 是一个非常好的建议(+1),但这仍然过于间接 - 必须假设目标是初始化调用者堆栈中存在的值。 :)
  • 是的,我知道的唯一方法就是使用新位置,但它会变得非常难看。移动构造函数可能是下一个最佳选择。
  • 因为编译器现在可以保证忽略复制或移动,您可以只声明一个复制或移动构造函数而不实现它。这样,您可以按值返回,但合法的复制/移动会产生链接器错误。
【解决方案2】:

复制省略,但它似乎是编译器优化,所以我认为它不适用。

确实如此。阅读更多Move or Named Return Value Optimization (NRVO)?

如何在不触发复制构造的情况下返回d

让编译器处理它。

【讨论】:

  • 嗯,我想做的是依靠类型系统来确保正确的代码。我想复制一个对象是一个类型错误。因为复制省略是一种优化,并且尽管语言语义说变量应该被复制,但它在这种情况下不适合我的需要。我所做的是通过 ref 传递“out”参数,并通过 const ref 传递“in”参数 - 这并不完美,但工作正常,并且消除了从函数返回值而不从语义上复制它的任何需要.
  • 我看到@jcarpenter。为什么不接受我的回答?你想让我根据你的评论修改它吗?我会说保持这种状态并在此处留下您的评论。
  • 我实际上触发了一个没有触发 NRVO 的情况,尽管它几乎和你上面的情况一样简单。
  • @gsamaras 因为它没有回答问题。我想在这里依靠类型系统
猜你喜欢
  • 1970-01-01
  • 2020-11-03
  • 2016-10-06
  • 2013-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多