Bug of the week #8


Welcome to the next pikoTutorial!

The error we’re handling today is a C++ compilation error:

error: use of deleted function X

What does it mean?

In C++, the error occurs when you try to invoke a function that has been explicitly marked as deleted or implicitly deleted by the compiler. This error commonly arises in relation to special member functions such as constructors, copy constructors, assignment operators etc. Functions can be explicitly deleted by the programmer to prevent certain operations or they can be implicitly deleted when certain conditions make them invalid (e.g. if a class member is non-copyable).

How to fix it?

Fixing depends on the situation in which the error occurred. Below you find some examples of such situations.

Function has been explicitly deleted

In C++ every function can be explicitly deleted, for example:

class File
{
public:
    void Read() = delete;
};

So when you try to use the Read() function in your code, like below, you’ll get the compilation error:

int main() {
    File file;
    
    file.Read(); // error: use of deleted function ‘void File::Read()’
}

In this case, if you own the File class, you can think about removing delete from Read() function and if you don’t own it, you must simply adjust your code, so that it doesn’t use the deleted function.

Copy constructor has been explicitly deleted

If the class you’re using has explicitly deleted copy constructor, for example:

class File
{
public:
    File() = default;
    File(const File&) = delete;
    File(File&&) = default;
};

Every attempt to copy it, for example by passing by value to a function, will result in the compilation error:

int main() {
    File file;
    
    ProcessFile(file); // error: use of deleted function ‘File::File(const File&)’
}

If you own the type which you’re using, the type can be copied and you actually need to copy it around, just adjust the File implementation so that it allows for copying. If you don’t own it, you may need to move it instead of copying it.

int main() {
    File file;
    
    ProcessFile(std::move(file));
}

Have in mind however that moving may be related with some consequences, so pay attention so that it doesn’t breake the rest of your code.

Copy constructor has been implicitly deleted

Sometimes it happens that you implement your own class and you don’t delete the copy constructor, but the compiler still complains about the copy constructor being deleted:

class File
{
private:
    std::mutex mtx_;
};

void ProcessFile(File file) {}

int main() {
    File file;
    
    ProcessFile(file); // error: use of deleted function ‘File::File(const File&)’
}

That’s because one of the members of your class, in this case std::mutex, has a deleted copy constructor, so the compiler implicitly deletes the copy constructor of your class as well. The compiler does this because it cannot generate a valid copy constructor if one of the class’s members is non-copyable.

In such case, you should really rethink if you should allow for your class to be copied because its non-copyable member prevent copying for a reason. But if you are absolutely sure that your class should have an enabled copy constructor, you can do that by defining your custom copy constructor in which you explicitly say what to do with the problematic, non-copyable member. In the simplest case, you could choose not to copy it at all, as shown in the example below:

class File
{
public:
    File() = default;
    File(const File&)
    : mtx_{} // Just initialize a new mutex
    {}
private:
    std::mutex mtx_;
};