Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ default move assignment operator cannot be invoked on class even if class has no constructors defined

Tags:

c++

c++14

While I was making myself familliar with C++14 specification, I have read that, if a class has no explicitly declared Copy Constructor, Copy Assignment Operator, Move Constructor nor Move Assignment Operator, default implementations should be generated by the compiler.

Consider this empty class for thread safe files:

class ThreadSafeFile
{
    std::mutex m_mutex;
    std::string m_FileName;
    std::ofstream m_File;
};

When I try to move assign it like this:

ThreadSafeFile file;

ThreadSafeFile file2 = std::move(file);

I am getting this compilation error:

function "ThreadSafeFile::ThreadSafeFile(const ThreadSafeFile &)" (declared implicitly) cannot be referenced -- it is a deleted function

Why is that so?

like image 882
Alexander Demerdzhiev Avatar asked Dec 19 '22 12:12

Alexander Demerdzhiev


2 Answers

If you look carefully, std::mutex cannot be copied nor moved. Since you have a member that cannot be moved or copied, your move constructor and copy constructor are implicitly deleted. If you want to allow moving your class, you can always use std::unique_ptr.

struct ThreadSafeFile {
    std::unique_ptr<std::mutex> m_mutex;
    string m_FileName;
    std::ofstream m_File;
};

As T.C pointed out in the comments, implementing a move constructor that moves everything except the mutex can also be a valid solution for some cases. You can find a very good example here: How should I deal with mutexes in movable types in C++?

like image 176
Guillaume Racicot Avatar answered Dec 21 '22 03:12

Guillaume Racicot


Because std::mutex is not movable nor copyable (they're deleted) so your class' move constructor (and copy constructor) are implictly deleted as well.

Quoting cppreference:

std::mutex is neither copyable nor movable.

You get the complaint for the copy constructor because the move constructor has failed already (without giving you diagnostics about it) and as a fallback the copy constructor is invoked and fails as well, once that happens, you get an error.

ThreadSafeFile file2 = std::move(file);
//ThreadSafeFile::ThreadSafeFile(ThreadSafeFile&&) fails.

//try Copy con (implicitly):
ThreadSafeFile file2(file); 
//ThreadSafeFile::ThreadSafeFile(const ThreadSafeFile&) fails too.

//Error.

As for the reasoning why they're deleted, there's an answer for that already.

like image 37
Hatted Rooster Avatar answered Dec 21 '22 02:12

Hatted Rooster