Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are there any use cases for a class which is copyable but not movable?

After reading this recent question by @Mehrdad on which classes should be made non-movable and therefore non-copyable, I starting wondering if there are use cases for a class which can be copied but not moved. Technically, this is possible:

struct S
{
    S() { }
    S(S const& s) { }
    S(S&&) = delete;
};

S foo()
{
    S s1;
    S s2(s1); // OK (copyable)
    return s1; // ERROR! (non-movable)
}

Although S has a copy constructor, it obviously does not model the CopyConstructible concept, because that is in turn a refinement of the MoveConstructible concept, which requires the presence of a (non-deleted) move constructor (see § 17.6.3.1/2, Table 21).

Is there any use case for a type like S above, which is copyable but not CopyConstructible and non-movable? If not, why is it not forbidden to declare a copy constructor and a deleted move constructor in the same class?

like image 403
Andy Prowl Avatar asked Jan 14 '13 17:01

Andy Prowl


People also ask

How do I make my class non copyable?

class NonCopyable { public: NonCopyable (const NonCopyable &) = delete; NonCopyable & operator = (const NonCopyable &) = delete; protected: NonCopyable () = default; ~NonCopyable () = default; /// Protected non-virtual destructor }; class CantCopy : private NonCopyable {};

How can we prevent copying or copy assigning any instance of a class?

There are three ways to prevent such an object copy: keeping the copy constructor and assignment operator private, using a special non-copyable mixin, or deleting those special member functions. A class that represents a wrapper stream of a file should not have its instance copied around.

Can an abstract class be copied?

Abstract Classes should be non copy-assignable.


1 Answers

Suppose you have a class that is no cheaper to move than it is to copy (perhaps it contains a std::array of a POD type).

Functionally, you "should" make it MoveConstructible so that S x = std::move(y); behaves like S x = y;, and that's why CopyConstructible is a sub-concept of MoveConstructible. Usually if you declare no constructors at all, this "just works".

In practice, I suppose that you might want to temporarily disable the move constructor in order to detect whether there is any code in your program that appears more efficient than it really is, by moving instances of S. To me it seems excessive to forbid that. It's not the standard's job to enforce good interface design in completed code :-)

like image 131
Steve Jessop Avatar answered Sep 20 '22 14:09

Steve Jessop