134

When/why would I want to explicitly delete my constructor? Assuming the reason is to prevent its usage, why not just make it private?

class Foo { public: Foo() = delete; }; 
3
  • 18
    It kind of goes nicely with = default, not even the class can use it, and I personally prefer seeing Use of deleted function. over Function is private. The former explicitly states "This is not meant to be used." If anything comes out of that, the class not being able to use it actually makes a semantical difference. Commented Dec 1, 2012 at 0:03
  • 12
    Since I rarely use C++11, this is more informative to me than the OP probably even realizes. I didn't even know you could tag a constructor for delete. Both the question and Luchian's answer easily qualify as constructive. Anyone not breathing the finer points of C++ 11 but will need to soon will get something out of both. Commented Dec 1, 2012 at 6:21
  • 1
    Possible duplicate of What's the point of deleting default class constructor? Commented Feb 25, 2018 at 16:46

4 Answers 4

132

How about:

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

versus

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

They're basically different things. private tells you that only members of the class can call that method or access that variable (or friends of course). In this case, it's legal for a static method of that class (or any other member) to call a private constructor of a class. This doesn't hold for deleted constructors.

Sample here.

Sign up to request clarification or add additional context in comments.

5 Comments

You do not need to declare Foo() at all, if you declare Foo(int). Foo() will not be generated and thus Foo f is invalid anyway. So your example does not show the case for deleted constructor. See for yourself - ideone.com/mogiIF
@mark I wrote 2 constructors to prove the point. I'll edit so it's clear to everyone.
I understand the difference, I just do not understand the added value of the delete statement in general and for a constructor in particular. After all, I could specify a private default constructor without the body. Then the code also fails, only during the linking. Well, I can see that delete conveys the intention more explicitly, but that's about it.
@mark Yes, that would be the C++98 way of doing things. But IMHO, conveying the intention clearly is actually a very important thing in programming in general. In this case, some readers may see a private undefined constructor and assume it's accidental and just add a definition for it, especially if the definition is as trivial as a default constructor (Yes, having a comment helps, but we'd much prefer compiler-enforcement over comment-enforcement). By having our intent clearer, we also get a much better error message which says "explicitly deleted" rather than "undefined reference".
I honestly don't understand how this answers the main question. The question in the title and OP's first question in the post was: When/why would I want to explicitly delete my constructor?
28

Why explicitly delete the constructor?

Another reason:

I use delete when I want to assure that a class is called with an initializer. I consider it as a very elegant way to achieve this without runtime checks.

The C++ compiler does this check for you.

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

This - very simplified - code assures that there is no instantiation (default construction) like this: Foo foo;

4 Comments

The deleted declaration is unnecessary here. It's automatically deleted with any user-provided constructor
To clarify the comment by @MikeLui, the deleted declaration is unnecessary to the compiler. There are numerous cases when code like this should be included to declare intent to other programmers.
Along with declaring your intent, it creates an obvious place to document your reason for its deletion in the public interface, and additionally the compiler error will be something short like "use of deleted function". If Foo had numerous constructors, just not a default one, then Foo foo; would cause a much longer error listing all implicitly defined, protected and private constructors it failed to match.
I still don't get how extra line with declaration of constructor wich "= delete" keyword declares intention of "no default constructor" idea better than ... just no default constructor? Sample: I don't want to declare variable "a" in my code - what is better, to write "// int a; // no need to define variable a" or just write nothing about this variable in code?
5

tl;dr

Explicit delete always works and gives more understandable error messages. Private declaration should no longer be used to prevent calls!

Detailed explanation

If you declare a function private, then it can still be called. In the case of a constructor, for example, from a static or a friend function.

With an explicit deletion of a function you express that it must never be used. This leads especially to clearly understandable error messages when trying to call such a function.

In the following class we do not have a default constructor because there is no meaningful way to implement it. The class contains a reference and it needs some object to point to.

class Foo { private: int& ref_; public: Foo(int& ref) : ref_(ref) {} }; int main() { Foo(); } 
$ g++ main.cpp main.cpp: In function ‘int main()’: main.cpp:10:9: error: no matching function for call to ‘Foo::Foo()’ 10 | Foo(); | ^ main.cpp:6:5: note: candidate: ‘Foo::Foo(int&)’ 6 | Foo(int& ref) : ref_(ref) {} | ^~~ main.cpp:6:5: note: candidate expects 1 argument, 0 provided main.cpp:1:7: note: candidate: ‘constexpr Foo::Foo(const Foo&)’ 1 | class Foo { | ^~~ main.cpp:1:7: note: candidate expects 1 argument, 0 provided main.cpp:1:7: note: candidate: ‘constexpr Foo::Foo(Foo&&)’ main.cpp:1:7: note: candidate expects 1 argument, 0 provided 

Deleting the constructor makes the error message short and understandable.

class Foo { private: int& ref_; public: Foo() = delete; Foo(int& ref) : ref_(ref) {} }; int main() { Foo(); } 
$ g++ main.cpp main.cpp: In function ‘int main()’: main.cpp:11:9: error: use of deleted function ‘Foo::Foo()’ 11 | Foo(); | ^ main.cpp:6:5: note: declared here 6 | Foo() = delete; | ^~~ 

If we solve this via a private declaration (without definition, which is impossible), the message looks similar at first.

class Foo { private: int& ref_; Foo(); public: Foo(int& ref) : ref_(ref) {} }; int main() { Foo(); } 
$ g++ main.cpp main.cpp: In function ‘int main()’: main.cpp:12:9: error: ‘Foo::Foo()’ is private within this context 12 | Foo(); | ^ main.cpp:5:5: note: declared private here 5 | Foo(); | ^~~ 

This works great as long as you don't call the constructor from a context where the private section of the class is accessible. As written above, this can be for example a static or a friendly function. In principle, it can also be a normal function, although this use case is rather rare.

class Foo { private: int& ref_; Foo(); public: Foo(int& ref) : ref_(ref) {} static Foo create() { return Foo(); // compiles fine } void foo() { Foo(); // compiles fine } friend void bar(); }; void bar() { Foo(); // compiles fine } int main() {} 
g++ -c -o main.o main.cpp 

This compiles completely without problems, the compile simply assumes that there will be a definition of Foo::Foo() somewhere else. As soon as the linker has to make an executable out of it, it will report the missing definition.

$ g++ main.o # or as one step with compilation and linking $ g++ main.cpp /usr/bin/ld: /tmp/ccnhLDsv.o: in function `bar()': main.cpp:(.text+0x23): undefined reference to `Foo::Foo()' collect2: error: ld returned 1 exit status 

Such errors are often extremely difficult to debug because they are stuck anywhere in the code base and you have no clue which file, let alone which line, the error is in.

An explicit delete, on the other hand, provides three precise error messages at the three locations where the errors are located.

class Foo { private: int& ref_; public: Foo() = delete; Foo(int& ref) : ref_(ref) {} static Foo create() { return Foo(); // error } void foo() { Foo(); // error } friend void bar(); }; void bar() { Foo(); // error } int main() {} 
$ g++ main.cpp main.cpp: In static member function ‘static Foo Foo::create()’: main.cpp:10:20: error: use of deleted function ‘Foo::Foo()’ 10 | return Foo(); // error | ^ main.cpp:6:5: note: declared here 6 | Foo() = delete; | ^~~ main.cpp: In member function ‘void Foo::foo()’: main.cpp:14:13: error: use of deleted function ‘Foo::Foo()’ 14 | Foo(); // error | ^ main.cpp:6:5: note: declared here 6 | Foo() = delete; | ^~~ main.cpp: In function ‘void bar()’: main.cpp:21:9: error: use of deleted function ‘Foo::Foo()’ 21 | Foo(); // error | ^ main.cpp:6:5: note: declared here 6 | Foo() = delete; | ^~~ 

Additional information

void foo(int need_integer) {} int main() { foo(5.4); // might trigger a warning, but compiles } 

Note that delete can also be used for normal functions. For example, to prevent implicit conversions.

void foo(int need_integer) {} void foo(double) = delete; int main() { foo(5); // okay foo(5.4); // error } 
$ g++ main.cpp main.cpp: In function ‘int main()’: main.cpp:6:8: error: use of deleted function ‘void foo(double)’ 6 | foo(5.4); // error | ~~~^~~~~ main.cpp:2:6: note: declared here 2 | void foo(double) = delete; | ^~~ 

1 Comment

Great input. It really helps while dealing with compile errors.
2

I've met with default ctors declared as 'deleted' in the source code of LLVM (in AlignOf.h for instance). The associated class templates are usually in a special namespace called 'llvm::detail'. The whole purpose there I think was that they considered that class only as a helper class. They never intended to instantiate them; only to use them within the context of other class templates with some metaprogramming tricks that run in compile time.

Eg. there's this AlignmentCalcImpl class template which is used only within another class template called AlignOf as a parameter for the sizeof(.) operator. That expression can be evaluated in compile time; and there's no need to instantiate the template -> so why not declare the default ctor delete to express this intention.

But it's only my assumption.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.