Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

what are use cases (if any) to make a class non-moveable?

Tags:

c++

boost

move

Consider a classic approach to make a class non copyable:

// similar to boost::noncopyable
class noncopyable
{
protected:
    constexpr noncopyable() = default;

    noncopyable(const noncopyable&) = delete;
    noncopyable& operator=(const noncopyable&) = delete;
};

class c: private noncopyable
{ /* ... */ };

As declaring any copy operation prevents auto-generation of move operations, this automatically makes all derived classes non moveable (by default) also (so full name of noncopyable would be noncopyable_and_nonmoveable).

Now let's look for classic noncopyable classes from the standard library, e.g. unique_ptr. It's noncopyable but moveable, otherwise its utility would be limited. I suppose same is true for many other cases.

Actually I cannot come up with any example when a class should be made non moveable. My argument is: even if a class is not planned to be moved there's a little chance this would be done by a mistake that can cause a harm.

It's actually two related questions:

1) Why boost::noncopyable is non moveable also? This causes issues, consider:

struct c: private boost::noncopyable
{
    std::unique_ptr<Something> something;

    c(c&&) = default;
    c& operator=(c&&) = default;
};

doesn't work (wandbox) - move operations cannot be generated because they are not generated for the base class. You need to implement them manually -> list your members -> maintenance -> bugs. Just defaulting move operations in noncopyable would solve the problem.

2) What are use cases when moveability is harmful so it should be prevented?

like image 471
Andriy Tylychko Avatar asked Oct 10 '17 11:10

Andriy Tylychko


2 Answers

Non-moveable gives you more control over object identity.

If an object is moveable, the address of it can change:

moveonly a;
b = std::move(a);

Now, anyone how still has a reference to a points to a stale object or (something else entirely).

Other situations where this arises is when you have external logic depending on object identity ("address stability") if you will, like e.g. with pthread mutexes: Move constructor for std::mutex

Addendum - The naming convention scoped_XXXX is oft used to imply non-moveable types (i.e. types guaranteeing immutable instance identity). Contrast this with e.g. unique_XXXX which implies a unique instance, that may be moved around. Note however, the standard library did not adopt this naming convention in full: Example: std::lock_guard<> vs std::unique_lock<>. C++17 amends this a bit

like image 146
sehe Avatar answered Sep 28 '22 01:09

sehe


1) Why boost::noncopyable is non moveable also?

Very most likely, historical reasons. boost::noncopyable is supposed to work with pre-C++11 compilers. There's actually very little reason to inherit from boost::noncopyable when using C++11 and beyond. If it were moveable in C++11, how do we establish the same move semantics in C++03 compilers?

2) What are use cases when moveability is harmful so it should be prevented?

non-moveablity should apply to kinds of resources that are supposedly given to you be an external system - Such as synchronization primitives, objects that represents stuffs like your computer's ACPI platform, and more.

like image 31
WhiZTiM Avatar answered Sep 28 '22 02:09

WhiZTiM