12

Earlier today I asked a question that led to another one: When should I use =delete? I don't think there is a post dedicated solely to =delete on SO, so I looked it up in a book called "The C++ Programming Language". I will list my findings in my answer below.

Please comment or answer if there's more to say or if I'm mistaken.

Community
  • 1
  • 1
Oleksiy
  • 37,477
  • 22
  • 74
  • 122
  • @Rapptz I saw that post, but I thought it was about what `=default` and `=delete` **do**. This one is about real uses of `=delete`. It's easy to understand that `=delete` disallows the use of the function, but why on Earth would you want to do that? This post answers why. – Oleksiy Sep 17 '13 at 05:21
  • "This question already has an answer here..." - um, no it doesn't. Even though these questions are related, they aren't duplicates. – Oleksiy Sep 19 '13 at 03:28

1 Answers1

30

It turns out that =delete is extremely useful! Here are a few examples:


Basically we can prevent copying base classes because it might often lead to slicing:

struct Base {

    Base(){}

    Base& operator=(const Base&) = delete; // disallow copying
    Base(const Base&) = delete;

    Base& operator=(Base && ) = delete;      // disallow moving
    Base(Base && ) = delete;

};

struct Der : public Base {};

void func() {

    Der d;
    Base base = d; // this won't work because the copy constructor is deleted!
                   // this behavior is desired - otherwise slicing would occur

}

It's also useful when a template function cannot run with a certain type:

template<class T>
void fn(T p) { /* ... */ }; // do something with T

void fn(int) = delete; // disallow use with int

void fun() {

    fn(4);      // aha! cannot use fn() with int!
    fn(-4.5);   // fine
    fn("hello");// fine
}

=delete can also disallow undesired conversions:

struct Z {

    Z(double); // can initialize with a double
    Z(int) = delete; // but not with an integer

};

void f() {

    Z z1 { 1 }; // error! can't use int
    Z z2 { 1.0 }; // double is ok

}

Some more advanced uses of =delete include prohibiting stack or free store allocation:

class FS_Only {
    ~FS_Only() = delete;  // disallow stack allocation
};

class Stack_Only {
    void* operator new(size_t) = delete;   // disallow heap allocation
};

... You get the idea. Hope this helps someone! =delete can help write readable, bugless and elegant code.


Edit:

As it was correctly pointed out in the comments, it is now impossible to delete FS_Only objects, so this one isn't such a good use of =delete after all.

Oleksiy
  • 37,477
  • 22
  • 74
  • 122
  • 1
    Wow, the only use I knew was to disallow copying. I don't expect so many other uses. – Siyuan Ren Sep 17 '13 at 05:19
  • 4
    The destructor is called also when you `delete` an object allocated on the heap, so by marking the destructor as deleted you make a class that can you can use to allocate on the heap but *never* delete. – Some programmer dude Sep 17 '13 at 05:21
  • 1
    Wow, with each new revision of the C++ spec. it becomes less and less recognizable as a language. This sounds useful, but boy that syntax is a total eyesore for a dinosaur like me. – Andon M. Coleman Sep 17 '13 at 05:21
  • I agree with Andon, the =delete syntax, which is supposed to be an 'annotation' is just fighting with the rest of the syntax. – rano Sep 17 '13 at 05:23
  • @JoachimPileborg thank you, you are correct, I'll edit my post in a minute to address that. – Oleksiy Sep 17 '13 at 05:23
  • 4
    @AndonM.Coleman I honestly have no idea why it would be considered complex (is it the reuse of a keyword? If so, context clues would help here). The syntax is incredibly clear IMO for C++ syntax. I'm fairly sure there are much more complex syntax that comes from C such as function pointers. – Rapptz Sep 17 '13 at 05:26
  • @Rapptz: Well, back when I started out in C++ the only time you would ever use `=` on the right-hand side of a function declaration was to denote it was pure-virtual. And this actually made a little bit of sense, but how does assigning a function `delete` make any sense? It just messes with people who have been coding in C++ for 20 years. – Andon M. Coleman Sep 17 '13 at 05:38
  • @rano The problem with annotations (if that's what you meant) is that they do NOT change the semantics of the code - only 'decorate' it. Whereas the `=delete` and `=default` are much more than mere decorations. @Oleksiy It's also worth mentioning that `=delete` is easier to diagnose than private -let's say- copy ctor, as it doesn't disallow private copying (if that is also to be forbidden) and will raise 'strange' non-defined errors. – Red XIII Sep 17 '13 at 05:42
  • @Red XIII by putting the quotes I was meaning something different than canonical annotations : ) The idea is that `=delete' stands on a meta level – rano Sep 17 '13 at 05:55
  • +1 for mentioning elegancy and C++ together. It has been *so* long. – nurettin Sep 17 '13 at 06:00
  • Keep in mind that new syntax should not break existing code, and ISO is fairly liberal there: even low quality code may have value, and shouldn't stop working for petty reasons. The reuse of existing keywords is safe in that respect: they couldn't have been used anywhere in existing code. – MSalters Sep 17 '13 at 06:07
  • @Oleksiy: regarding the slicing issue, actually I prefer using `=default` and defining defaulted copy/move operations as `protected` so that the `Derived` class has natural copy/move semantics (automatically implemented by the compiler) and slicing is still presented. – Matthieu M. Sep 17 '13 at 06:37
  • @Oleksiy How does deleting destructor prevents allocation? I've never seen this convention, so I'm curious about it. – jnovacho Sep 17 '13 at 08:53
  • @jnovacho I have an answer for you, but it's way too long for a comment (it has code examples too). I will answer it if you formally ask this question and post a link to it in a comment under this. Your question **is** a question after all, not a comment. – Oleksiy Sep 17 '13 at 09:13
  • @Oleksiy Please add the following example: having an overload `void f(const T&& )=delete` where `T` is deduced. As far as I know (haven't tried though), you cannot call `f` with temporaries. – Ali Sep 17 '13 at 09:19
  • @Oleksiy Great answer by the way! +1 – Ali Sep 17 '13 at 09:20
  • @Oleksiy Done. Question -> http://stackoverflow.com/questions/18847739/how-does-delete-on-destructor-prevents-allocation – jnovacho Sep 17 '13 at 10:45
  • Shouldn't you solve the `fn` problem via specialization rather than overloading? – user541686 Aug 25 '15 at 18:34