gpt4 book ai didi

c++ - 何时使用 =default 与 =delete

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:16:08 25 4
gpt4 key购买 nike

据我了解,这些语义仅用于复制构造函数、移动构造函数、复制赋值、移动赋值和析构函数。使用 = delete用于禁止使用其中一项功能,即= default如果您想向编译器明确说明在何处使用这些函数的默认值,则使用它。

在制作类(class)时使用这些关键字的最佳做法是什么?或者更确切地说,在开发类(class)时我如何记住这些?

例如,如果我不知道我是否会使用这些功能之一,最好用 delete 禁止它。或允许并使用 default ?

最佳答案

好问题。

同样重要的是:哪里使用 = default= delete .

我对此有一些有争议的建议。它与我们所有人(包括我自己)为 C++98/03 学到的东西相矛盾。

用你的数据成员开始你的类声明:

class MyClass
{
std::unique_ptr<OtherClass> ptr_;
std::string name_;
std::vector<double> data_;
// ...
};

然后,尽可能接近实际,以可预测的顺序列出您想要显式声明的所有六个特殊成员(不要列出您希望编译器处理的成员)。我喜欢的顺序是:
  • 析构函数// this tells me the very most important things about this class.
  • 默认构造函数
  • 复制构造函数// I like to see my copy members together
  • 复制赋值运算符
  • 移动构造函数// I like to see my move members together
  • 移动赋值运算符

  • 这个命令的原因是:
  • 无论您默认什么特殊成员,如果读者知道数据成员是什么,他们就更有可能理解默认值的作用。
  • 通过在靠近顶部的一致位置并以一致的顺序列出特殊成员,读者更有可能快速意识到哪些特殊成员没有显式声明 - 因此要么隐式声明,要么根本不存在。
  • 通常,两个复制成员(构造函数和赋值)是相似的。两者都会
    隐式默认或删除,显式默认或删除,或显式提供。很高兴在彼此相邻的两行代码中确认这一点。
  • 通常两个移动成员(构造函数和赋值)是相似的...

  • 例如:
    class MyClass
    {
    std::unique_ptr<OtherClass> ptr_;
    std::string name_;
    std::vector<double> data_;
    public:
    MyClass() = default;
    MyClass(const MyClass& other);
    MyClass& operator=(const MyClass& other);
    MyClass(MyClass&&) = default;
    MyClass& operator=(MyClass&&) = default;
    // Other constructors...
    // Other public member functions
    // friend functions
    // friend types
    // private member functions
    // ...
    };

    知道了约定,就可以很快看到,而无需检查 ~MyClass() 的整个类声明。是隐式默认的,并且数据成员就在附近,很容易看出编译器声明和提供的析构函数做了什么。

    接下来我们可以看到 MyClass有一个显式默认的默认构造函数,并且在附近声明了数据成员,很容易看出编译器提供的默认构造函数做了什么。也很容易看出为什么显式声明了默认构造函数:因为我们需要一个用户定义的复制构造函数,如果没有显式默认,这将禁止编译器提供的默认构造函数。

    接下来我们看到有一个用户提供的复制构造函数和复制赋值运算符。为什么?好吧,有了附近的数据成员,很容易推测可能是 unique_ptr ptr_ 的深层拷贝。需要。如果不检查复制成员的定义,我们当然无法确定。但即使没有这些定义,我们也已经很了解了。

    对于用户声明的复制成员,如果我们什么都不做,移动成员将不会被隐式声明。但是在这里我们很容易看到(因为所有内容都在 MyClass 声明的顶部进行了可预测的分组和排序)我们已经明确默认了移动成员。同样,因为数据成员就在附近,我们可以立即看到这些编译器提供的移动成员会做什么。

    总之,我们还不知道究竟是什么 MyClass有什么作用以及它将在这个程序中扮演什么角色。然而,即使缺乏这些知识,我们也已经对 MyClass 了解了很多。 .

    我们知道 MyClass :
  • 持有指向某些(可能是多态的)的唯一拥有指针 OtherClass .
  • 保存一个字符串作为名称。
  • 保存一堆 double 作为某种数据。
  • 会正确地自毁而不会泄漏任何东西。
  • 将默认构造自身为空 ptr_ , 空 name_data_ .
  • 会复制自己,具体如何复制,但我们可以在其他地方轻松检查可能的算法。
  • 将通过移动三个数据成员中的每一个来有效(且正确)移动自身。

  • 在 10 行左右的代码中,有很多东西需要了解。而且我们不必去寻找数百行代码,我确信这些代码是正确实现 MyClass 所必需的。学习这一切:因为一切都在顶部,并且按照可预测的顺序进行。

    人们可能想要调整这个秘籍,比如将嵌套类型放在数据成员之前,以便可以根据嵌套类型声明数据成员。然而,这个建议的精神是声明私有(private)数据成员和特殊成员,两者都尽可能靠近顶部实际,并尽可能靠近彼此。这与过去(甚至可能是我自己)给出的建议相反,私有(private)数据成员是一个实现细节,不重要到不能放在类声明的顶部。

    但是事后看来(事后看来总是 20/20),即使远程代码无法访问私有(private)数据成员(这是一件好事),但当它的任何特殊成员由编译器提供时,它确实会规定和描述类型的基本行为.
    了解类的特殊成员做什么,是理解任何类型的最重要方面之一。
  • 它是可破坏的吗?
  • 它是默认可构造的吗?
  • 可复制吗?
  • 它是可移动的吗?
  • 它是否具有值语义或引用语义?

  • 每种类型都有这些问题的答案,最好尽快解决这些问题和答案。然后,您可以更轻松地专注于使这种类型与其他类型不同的原因。

    关于c++ - 何时使用 =default 与 =delete,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27232943/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com