为什么显式删除构造函数?


93

什么时候/为什么要显式删除我的构造函数?假设原因是为了防止使用它,为什么不仅仅使用它private呢?

class Foo
{ 
  public: 
    Foo() = delete; 
};

14
它与很好地配合使用= default,即使是类也不能使用它,我个人更喜欢看到使用Deleted函数。函数是私有的。前者明确指出“这并不意味着要使用”。如果从中得出任何结果,则该类无法使用它实际上在语义上有所不同。
克里斯

15
老实说,我认为人们已经开始以亲密的票调相。我不认为这不是建设性的。
Luchian Grigore

4
@LuchianGrigore:同意。我一直想知道为什么社区本身变得如此僵硬。我不明白这一点。
Ed S.

11
由于我很少使用C ++ 11,因此这对我而言比OP甚至可能还多。我什至不知道您可以标记的构造函数delete。问题和陆谦的回答都容易被认为是建设性的。任何没有呼吸C ++ 11优点的人都需要尽快从这两者中受益。
WhozCraig

Answers:


87

怎么样:

//deleted constructor
class Foo
{ 
  public: 
    Foo() = delete;     
  public:
    static void foo();
};

void Foo::foo()
{
   Foo f;    //illegal
}

//private constructor
class Foo
{ 
  private: 
    Foo() {}     
  public:
    static void foo();
};

void Foo::foo()
{
   Foo f;    //legal
}

它们本质上是不同的东西。private告诉您只有该类的成员才能调用该方法或访问该变量(或当然是朋友)。在这种情况下,static该类(或任何其他成员)的方法调用private类的构造函数是合法的。这不适用于已删除的构造函数。

样品在这里


3
如果您声明Foo(int),则根本不需要声明Foo()。Foo()将不会生成,因此Foo f仍然无效。因此,您的示例没有显示删除构造函数的情况。自己看看-ideone.com/mogiIF
标记

1
@mark我写了2个构造函数来证明这一点。我将进行编辑,以使每个人都很清楚。
Luchian Grigore

1
我了解它们之间的区别,我只是不了解Delete语句的附加值,特别是对于构造函数。毕竟,我可以指定一个没有主体的私有默认构造函数。然后,该代码也仅在链接期间失败。好吧,我可以看到delete可以更明确地传达意图,但仅此而已。
标记

11
@mark是的,那将是C ++ 98的处理方式。但是恕我直言,明确传达意图实际上是总体上编程中非常重要的事情。在这种情况下,一些读者可能会看到私有的未定义构造函数,并认为它是偶然的,只是为其添加了一个定义,尤其是如果该定义与默认构造函数一样琐碎(是的,有注释会有所帮助,但我们更喜欢编译器-执行超过评论执行)。通过更清晰地了解我们的意图,我们还得到了一条更好的错误消息,该消息显示“被明确删除”而不是“未定义引用”。
mpark 2014年

2
老实说,我不明白这是如何回答主要问题的。标题中的问题和OP在帖子中的第一个问题是:什么时候/为什么要显式删除我的构造函数?
亚历山大·波林斯基

11

为什么显式删除构造函数?

另一个原因:
delete想确保使用初始化程序调用类时使用。我认为这是无需运行时检查即可实现的非常优雅的方法。

C ++编译器会为您执行此检查。

class Foo
{
   public:
       Foo() = delete;
       Foo(int bar) : m_bar(bar) {};
   private:
       int m_bar;
}

这是非常简化的代码,确保没有这样的实例化:Foo foo;


12
此处不需要删除的声明。它会由任何用户提供的构造函数自动删除
Mike Lui

5
为了澄清@MikeLui的注释,已删除的声明对于编译器而言是不必要。在很多情况下,应包含这样的代码来向其他程序员声明意图。
杰夫·G

在声明您的意图的同时,它在公共接口中创建了一个明显的地方来记录您删除它的原因,此外,编译器错误也很短,例如“使用已删除的函数”。如果Foo有许多构造函数,而不仅仅是默认构造函数,那么Foo foo;将导致更长的错误列出所有与之不匹配的隐式定义,受保护和私有构造函数。
sigma

我仍然不明白如何用构造函数的额外行声明“ = delete”关键字比“没有默认构造函数”更好地声明“没有默认构造函数”的意图?示例:我不想在代码中声明变量“ a”-更好的方法是编写“ // int a; //无需定义变量a”或只在代码中不写任何有关此变量的信息?
Ezh

2

我遇到了在LLVM的源代码中声明为“已删除”的默认ctor(例如,在AlignOf.h中)。关联的类模板通常位于称为“ llvm :: detail”的特殊命名空间中。我认为这里的全部目的是他们只将该课程视为帮助者课程。他们从来没有打算实例化它们。只能在具有编译时运行的一些元编程技巧的其他类模板的上下文中使用它们。

例如。这里有这个AlignmentCalcImpl类模板,该类模板仅在另一个名为AlignOf的类模板中用作sizeof(。)运算符的参数。该表达式可以在编译时求值;并且不需要实例化模板->那么为什么不声明默认的ctor delete来表达这种意图。

但这只是我的假设。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.