删除默认类构造函数有什么意义?

Der*_*son 50 c++ default-constructor

我正在准备我的CPP考试,其中一个问题是:你能否删除默认的类构造函数,如果是,那么这样做的原因是什么?好的,显然你可以这样做:

class MyClass 
{ 
  public: 
    MyClass() = delete; 
};
Run Code Online (Sandbox Code Playgroud)

但我不明白你为什么要这样做?

Que*_*tin 75

考虑以下课程:

struct Foo {
    int i;
};
Run Code Online (Sandbox Code Playgroud)

此类是聚合,您可以使用以下所有三个定义创建实例:

int main() {
    Foo f1;     // i uninitialized
    Foo f2{};   // i initialized to zero
    Foo f3{42}; // i initialized to 42
}
Run Code Online (Sandbox Code Playgroud)

现在,假设您不喜欢未初始化的值以及它们可能产生的未定义行为.您可以删除默认构造函数Foo:

struct Foo {
    Foo() = delete;
    int i;
};
Run Code Online (Sandbox Code Playgroud)

Foo 仍然是聚合,但只有后两个定义有效 - 第一个定义现在是编译时错误.

  • 或者,只需要`struct Foo {int i = 0; };`. (16认同)
  • @TC是对的,但我提出了这个例子很小的对立点,可能会有更复杂的情况,这可能会派上用场.不过,我自己无法想出一个. (7认同)

Arn*_*rah 46

删除默认构造函数有几个原因.

  1. 该类纯粹是静态的,您不希望用户仅使用静态方法/成员实例化类.这种类的一个示例可能是仅使用静态方法来创建新类的工厂设计模式.
  2. 具有默认构造函数的类是没有意义的(因为它需要参数/没有对该类有意义的默认值).在这种情况下,这= delete是一个样式的东西,正如@HolyBlackCat所说,但它通过告诉客户端代码用参数调用构造函数来澄清你的意图.
  3. 您不希望聚合类的未初始化数据.

如果第二个陈述不清楚,请考虑以下示例:

class A
{
public:
   //A() = delete; 
   A(int, int) {};
};
Run Code Online (Sandbox Code Playgroud)

如果您现在尝试调用默认构造函数,则会出现类似于(GCC 7.2)的错误:

错误:没有匹配函数来调用'A :: A()'

但是,如果您使用the取消注释该行= delete,那么您将获得以下内容:

错误:使用已删除的函数'A :: A()'

这明确表明,人们试图使用已删除的构造函数与其他错误进行比较,这有点不清楚.

  • @HolyBlackCat一个删除的函数.参与重载决议.例如,用`X(const X&)`用户声明,没有隐式声明移动c'tor,但是`X(std :: move(anotherX))`仍然可以工作,选择复制c'tor作为最接近的匹配.但如果移动c'tor被删除,则此代码变得格格不入.另外,如果你有一个可变参数,例如`X(Args && ...)`,这可以用来构造没有参数的对象,但是如果有一个删除的`X()`则不行.[参考](/sf/ask/1062699711/) (7认同)
  • 在第二种情况下,它会被自动删除,所以`= delete`将是一种风格的东西. (5认同)
  • @HolyBlackCat否......它将*未声明*,而不是*删除*.一个微妙但有时重要的区别.实际上,尝试使用前者会导致错误,例如"调用中没有匹配的构造函数...",而后者会导致错误,例如"默认构造函数在调用中被删除..."(我太懒了,无法检查确切的尽管如此,这取决于编译器.) (5认同)
  • @aschepler足够公平.命名空间模板虽然很酷. (4认同)

use*_*744 5

多个默认选择

当默认或未初始化状态有多个选项时,删除类的默认构造函数是个好主意.例如,假设我有一个班级,

template<typename F>
class Polynomial;
Run Code Online (Sandbox Code Playgroud)

表示场上的多项式,F.在这种情况下,多项式的默认值有很多选择.一个可能是加法下的多项式的同一性,即零,但我们也可以有乘法同一性,统一.这取决于用户打算如何推断该类以及如何使用它.


没有默认选择

另一个值得注意的情况是,在没有多个默认状态可能有意义的情况下,我们没有.例如,假设我们有一个表示流形或曲面的类.

那是Manifold()什么?它是一个空的空间,没有任何东西,没有表面,没有距离或公制的概念.但是将它看作一种流形是没有意义的,而是像拓扑空间那样更通用的东西.

所以,在这种情况下,我也会选择删除默认构造函数.


Pha*_*rap 5

有时候不打算对类进行实例化.

到目前为止尚未提及的一个例子是"特质"类.例如,考虑一下std::char_traits,虽然标准没有说它的默认构造函数需要删除,但是它的默认构造函数没用,因为类本身是空的,它的所有函数都是静态的,不需要实例化为使用它提供的类型别名.

Trait类通常只用于支持其他类(通常是其他模板类),因此删除它们的默认构造函数通常是有意义的 - 强化它们只是一个帮助类型并且不应该像它一样使用的概念一个东西.