How it works...

Move-only classes prevent a class from being copied, which in some cases, can be a performance improvement. Move-only classes also ensure a 1:1 relationship between resources that are created versus the resources that are allocated, as copies cannot exist. Moving a class, however, can result in a class becoming invalid, as in this example:

#include <iostream>

class the_answer
{
std::unique_ptr<int> m_answer;

public:

explicit the_answer(int answer) :
m_answer{std::make_unique<int>(answer)}
{ }

~the_answer()
{
std::cout << "The answer is: " << *m_answer << ' ';
}

public:

the_answer(the_answer &&other) noexcept = default;
the_answer &operator=(the_answer &&other) noexcept = default;
};

int main(void)
{
the_answer is_42{42};
the_answer is_what{42};

is_what = std::move(is_42);
return 0;
}

If we run the preceding code, we get the following:

In the preceding example, we create a class that can be moved, which stores std::unique_ptr. In the destructor of the class, we dereference the class and output its value. We don't check the validity of std::unique_ptr because we wrote a constructor that forces a valid std::unique_ptr, forgetting that a move can undo this explicit validity. The result is that, when a move is performed, we get a segmentation fault.

To overcome this, we need a reminder that we made this assumption, as follows:

class the_answer
{
std::unique_ptr<int> m_answer;

public:

explicit the_answer(int answer) :
m_answer{std::make_unique<int>(answer)}
{ }

~the_answer()
{
std::cout << "The answer is: " << *m_answer << ' ';
}

public:

the_answer(the_answer &&other) noexcept = delete;
the_answer &operator=(the_answer &&other) noexcept = delete;

the_answer(const the_answer &other) = delete;
the_answer &operator=(const the_answer &other) = delete;
};

The preceding class explicitly deletes both the copy and move operations, and this is our desired intent. Now, if we accidentally move this class, we get the following:

/home/user/book/chapter03/recipe07.cpp: In function ‘int main()’:
/home/user/book/chapter03/recipe07.cpp:106:30: error: use of deleted function ‘the_answer& the_answer::operator=(the_answer&&)’
is_what = std::move(is_42);
^
/home/user/book/chapter03/recipe07.cpp:95:17: note: declared here
the_answer &operator=(the_answer &&other) noexcept = delete;
^~~~~~~~

This error tells us that it is assumed that the class is valid and therefore does not support moving. We either need to properly support moving (which means we must maintain support for invalid std::unique_ptr) or we need to remove the move operation. As shown, a class that cannot be moved or copied can ensure that our code works as intended, providing the compiler with a mechanism to warn us when we are doing something with our class that we didn't intend.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset