C++ 我是否正确理解RAII与复制/交换习惯用法的结合?

C++ 我是否正确理解RAII与复制/交换习惯用法的结合?,c++,raii,copy-and-swap,C++,Raii,Copy And Swap,管理资源句柄(文件句柄、gpu句柄、互斥体)的类希望防止复制资源的句柄,因此包装类的解构会自动释放资源一次且仅一次,并且没有任何对象可以再访问句柄,因为对象的生存期已经结束,并且(希望如此)不再存在指向包装器的引用或指针 复制/交换和规则5(半)表示通常需要定义复制构造函数/赋值运算符。复制资源句柄显然是不需要的。我是否正确地理解,因此只要删除任何其他构造函数/赋值运算符就可以解决这个问题(如果我赋值时没有转换为右值(因此赋值完成后不再存在),编译器会对我大喊大叫) 这与这个问题有关,因为我想要

管理资源句柄(文件句柄、gpu句柄、互斥体)的类希望防止复制资源的句柄,因此包装类的解构会自动释放资源一次且仅一次,并且没有任何对象可以再访问句柄,因为对象的生存期已经结束,并且(希望如此)不再存在指向包装器的引用或指针

复制/交换和规则5(半)表示通常需要定义复制构造函数/赋值运算符。复制资源句柄显然是不需要的。我是否正确地理解,因此只要删除任何其他构造函数/赋值运算符就可以解决这个问题(如果我赋值时没有转换为右值(因此赋值完成后不再存在),编译器会对我大喊大叫)

这与这个问题有关,因为我想要构造的资源实际上只有在它们所属的包含数据结构已经构造好之后才可以构造,这就需要移动资源,而不是复制它们


删除资源句柄类的复制构造函数和复制赋值运算符非常有意义,它将产生所需的结果。(请注意,复制构造函数和复制赋值通常采用常量引用参数。这并不重要,因为运算符已被删除,但就我个人而言,除非有其他原因,否则我始终坚持常量引用。我发现这使代码更易于阅读。)

然而,“互换分配”是有问题的

首先,它不会像您的示例中所写的那样工作:

class Resource {
    Handle resource_handle;
public:
    friend void swap(Resource &a, Resource &b); // swap for the partial copy/swap idiom

    Resource(); // Default with uninitialized handle whose destruction is a noop
    Resource(std::string location); // Construction of resource (e.g. load something from disk)
    Resource(Resource &&other); // Move constructor to receive from returns of functions
    Resource &operator=(Resource other); // Sawp assignment to implement copy/swap idiom
    Resoruce(Resource &other) = delete; // You can not copy resources
    Resource &operator=(Resource &other) = delete; // You can not copy resources
};
此函数按值获取参数,从而创建副本。由于复制构造函数已删除,因此无法编译

第二,即使这样的事情真的起作用,也会产生误导。人们通常期望任务的右侧保持不变。我建议用交换方法替换“交换分配”:

Resource &operator=(Resource other);  // bad

然后,您可以使用此方法实现非成员交换函数,如果
swap
方法是公共的,它甚至不需要是友元函数。

FYI:如果您明确声明它们为
=delete
,则它们可以作为可能的替代方法,如果选择或不明确,将导致编译错误。但是,如果您允许编译器抑制它们,而从不合成它们,那么它们就根本不存在。这是一个重要的区别(有时是正确的,有时是错误的……取决于需要)。注意-
Resource&operator=(Resource-other);//Sawp分配…
将转换为临时分配,可能不是您想要做的。我还将使用
swap
成员函数来明确意图并删除赋值运算符。是否要将复制和交换与非可复制类一起使用?为什么?除了运算符=(资源)之外,您的方法是合理的。您可能还需要一个移动赋值操作符。(如果复制了移动的构造(Ak< C++ >代码>资源A=FoSE(Toes));资源/运算符=(资源和其他),拷贝仍然是可能的;代码>资源A=FUTHORY(THOTS);< /Cord>可以从临时调用移动构造函数。但是在现代C++(IE C++ 17中),在大多数情况下,它实际上会完全省略临时变量,允许
function()
直接构造
a
。“此函数按值获取参数,从而创建副本”-不正确。由于
Resource
有一个移动构造函数,调用方可以调用
操作符=
,将右值作为输入,从而移动构建
other
,而不是复制构建它。在这种情况下,最好定义
操作符=
以右值引用作为参数。但是如果
Resource
>确实支持复制构造函数,那么按值获取
other
实际上很有用,允许调用方根据需要选择是复制构造函数还是移动构造函数
other
,因此不需要单独的
操作符=
实现。我想更相关的情况是
资源a;a=函数(stuff);
因为资源希望成为包含类的成员,但需要在以后构建和初始化。例如,我想在这里做的事情:
void swap(Resource& other);