c++ - 从函数返回一个 RAII 对象
问题描述
在 C++14 中,我试图定义一个“RAII 工厂”函数,如下所示:
// Here, "ScopedReseource" is a plain RAII class, managing some resource.
ScopedResource factory(/* args */) {
return ScopedReseource(/* args */);
}
客户使用情况将是:
{
auto scoped = factory(/* args */));
// use scoped...
}
据我了解,C++ 14 中的语言不保证复制省略,因此这是不可靠的。特别是,它可能导致 ScopedResource 的析构函数在factory()
函数结束时被调用(并在调用点生成一个新副本)。我不想要那个。
当然,传统的客户端代码可以正常工作:
{
ScopedResource scoped(/* args */);
// use scoped...
}
现在,我尝试删除ScopedResource
的复制构造函数 ( =delete
),并定义一个移动构造函数。代码编译,它只构造/破坏一次,这是我想要的——但它是可移植的吗?
所以,问题:
- 在 C++17 之前返回一个 RAII 对象(析构函数执行我想要完成一次的特殊工作)我是对的吗?
- 我删除复制构造函数并定义移动构造函数的方法是否有效/可移植?
- 我是对的,在 C++17 中,您可以使用上面的幼稚代码便携地做到这一点吗?
还是我在这里遗漏了其他一些细微差别?
解决方案
据我了解,C++ 14 中的语言不保证复制省略,因此这是不可靠的。特别是,它可能导致在 factory() 函数结束时调用 ScopedResource 的析构函数(并在调用点生成一个新副本)。我不想要那个。
为什么不?
如果您的类型是可移动的,那么这意味着被移动的对象将包含一个“空”资源。也就是说,它当前不会与资源相关联。因此,它的析构函数不会做任何事情,被管理的资源仍然存在。
所以在 C++14 中按值返回这样的对象是没有问题的。是的,析构函数可能会被调用,但既然它什么都不做,谁在乎呢?
在 C++17 之前返回一个 RAII 对象(析构函数执行我想要完成一次的特殊工作)我是对的吗?
不,你不正确。只要您将对象编码为具有表示没有资源的“空”状态(这是仅移动类型的标准),“特殊工作”将仅由单个对象完成。可能会调用多个析构函数,但只有一个这样的调用会完成释放资源的重要部分。
这是关于正确实现仅移动类型,而不是关于复制省略。
推荐阅读
- reactjs - reactjs中如何在Router Link(菜单导航)中传递多个状态
- python - 在 python 中运行 fortran 子例程时出现奇怪的错误
- php - 由于未正确配置 htaccess 文件,POST 无法正常工作
- java - 使用 Javamail 无法接收来自 POP3 GMAIL 的邮件,出现 SSLHandshakeException
- python - 无法使用循环预测 Keras 中的单个实例
- php - 将 jquery 对象附加到 formData()
- python - tkinter 输入字段的遍历顺序有问题
- bash - 从 awk 生成的制表符分隔文件填充关联数组的疑难解答
- email - 如何在邮箱参数中使用变量?
- r - 如何将一个数据框的列除以另一个数据框的列