Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

undefined vs. deleted vs. undeclared function

Tags:

c++

c++11

I am using the default constructor as an example here, but the same question applies to all the special member functions.

Also, I am using https://en.cppreference.com instead of the standard because that is what I am reading and that is what I am having trouble understanding. If using the standard would change the question in any way, please let me know.


As stated in https://en.cppreference.com/w/cpp/language/default_constructor, if a class has no constructor then the compiler will always declare a default one. Then, if certain conditions aren't met, it will be undefined (pre c++11) or defined as deleted (post c++11).

All this seems to imply that there is a difference between a function being not declared, declared but not defined, or declared and deleted. However, all three options won't compile/link, e.g.

class MyClass {
public:
    void foo();
    void bar() = delete;
};

int main() {
    MyClass c;
    //c.foo();  // won't link
    //c.bar();  // won't compile
    //c.baz();  // won't compile
}

So why is it so important to change the definition from "declared and undefined" to "declared and deleted", and why not just leave it as "undeclared" in the first place?

like image 230
Baruch Avatar asked Oct 22 '19 12:10

Baruch


2 Answers

So why is it so important to change the definition from "declared and undefined" to "declared and deleted"

Because of the difference: "won't link" vs "won't compile". This is a fundamental reason for why = delete was introduced: To catch the bugs of using (previously) undefined functions at compile time, rather than later. Furthermore, it allows better error diagnostic, since the compiler will be able to describe why the function is deleted. The best that the linker can say is that nobody defined it for some unknown reason.

There's no reason not to take advantage of the feature with the implicitly generated member functions.

like image 124
eerorika Avatar answered Sep 30 '22 01:09

eerorika


The = deleted; declaration can be useful in various situations. As well as the very good reason given by eerorika, it can also be used to explicitly declare that a given 'special' function, such as the default constructor doesn't exist, and cannot be called.

It can also be used to specify that a function which exists in a base class does not exist in a derived class (which, by default, it will).

Here's a short piece of code showing such usage:

#include <iostream>

class foo {
private:
    int m;
public:
    foo() = delete; // Other programmers reading this definition will know immediately!
    foo(int n) : m{ n } {} // ... that default ctor is intended not to be used
    void inc() { ++m; }    // ... rather than it has been omitted accidentally
    int get() { return m; }
};
class bar : public foo {
public:
    bar() : foo(0) {}
    void inc() = delete; // Without this, code like `bar b; b.inc();` will call foo.inc()
};

int main() {
//  foo f1; // error C2280: 'foo::foo(void)': attempting to reference a deleted function
    foo f2(3); std::cout << f2.get() << std::endl;
    f2.inc();  std::cout << f2.get() << std::endl;
    bar b1;    std::cout << b1.get() << std::endl;
//  b1.inc(); error C2280: 'void bar::inc(void)': attempting to reference a deleted function
    return 0;
}
like image 33
Adrian Mole Avatar answered Sep 30 '22 00:09

Adrian Mole