具有不可复制成员的复制赋值运算符

Posted

技术标签:

【中文标题】具有不可复制成员的复制赋值运算符【英文标题】:Copy assignment operator with non-copyable members 【发布时间】:2021-11-25 04:36:01 【问题描述】:

假设我有一个只有构造函数的类A

struct A

    A() = default;
    A(const A&) = delete;
    A& operator=(const A&) = delete;
;

我还有一个类B,其中包含A 的一个实例,并按如下方式定义了复制构造函数:

struct B

    B() = default;
    B(const B& other) : _a 
    A _a;
;

这里B 的构造函数只是用A 的新实例初始化_a。但是,我如何为B 编写赋值运算符(因为我不能“重新初始化”_a)?

【问题讨论】:

应该会发生什么?如果赋值运算符存在,是否可以给A 提供类似于reset 的方法,相当于调用operator=(A) 您有几个选择:(1) 忽略_a,在复制B 时不理会它。 (2) 使B 不可复制。 (3) 间接持有嵌入的A 实例,例如unique_ptr<A>而不是A,所以可以重制。 您可以尝试调用_a.~A() 并使用放置new 替换_a (new (&_a) A)。但是这个解决方案有一些微妙的问题,特别是A 构造函数不是noexcept。而且由于A 似乎不可移动,它可能代表了一种不寻常的资源并且并非微不足道。我会考虑使用std::unique_ptr<A> _a; 而不是直接使用A 也许我可以让 A “可移动”并为 B 的赋值运算符使用交换习语(因为 B 的复制构造函数存在)? 【参考方案1】:

如果您希望operator= 创建一个类似于复制构造函数的全新A,并且如果动态分配可行,您可以使用std::unique_ptr<A> 作为成员:

struct A

    A() = default;
    A(const A&) = delete;
    A& operator=(const A&) = delete;
;

struct B

    B() : _astd::make_unique<A>() 
    B(const B& other) : _astd::make_unique<A>() 
    B& operator=(const B& other) 
        _a = std::make_unique<A>();
        return *this;
    
    std::unique_ptr<A> _a;
;

不过,如果B 有一个不可复制(不可移动)的成员,那么最不令人惊讶的是B 也是不可复制(不可移动)的。

【讨论】:

运营商=你的意思是?【参考方案2】:

根据类A的定义,A的实例是不可复制的,也是不可移动的。因此,我接受了@463035818_is_not_a_number 的回答。

这是另一个答案,它假设 A 可以移动,只是为了完整性或可能对某人有用。

struct A

    A() = default;
    A(const A&) = delete;
    A& operator=(const A&) = delete;
    A(A&&) = default;
    A& operator=(A&&) = default;
;

struct B

    B() = default;
    B(const B&) : _a 
    B& operator=(B other)
    
        std::swap(_a, other._a);
        return *this;
    
    A _a;
;

【讨论】:

以上是关于具有不可复制成员的复制赋值运算符的主要内容,如果未能解决你的问题,请参考以下文章

派生自std :: exception的类的赋值运算符

c++中拷贝构造函数和赋值运算符重载本质上一样么

如何为具有自引用指针的类实现复制构造函数/赋值运算符?

重载赋值运算符

复制构造函数与赋值运算符(=)有何不同

c++ 拷贝构造函数与赋值运算符重载函数的区别是