Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I allow move construction and disallow assignment and copy construction of a class

Is there a way to allow a move constructor and disallow copy construction and assignment. I can think of several classes with file pointers and buffer pointers (resource handles etc) that would benefit from being copy constructed and assigned.

I am using VC2010 & GCC 4.5.2. I know that I would have to declare empty private assignment and copy constructors in the VC2010 class headers and as far as I am aware GCC allows some sort of delete signature after the method to do the same thing.

If anyone has a good example of a skeleton class like this and the advantages I would be very grateful. Thanks in advance John

Here is an example of a class for which I would like to allow moves but I would also like to prevent direct asssignment. Is it simily a matter of making the copy constructor and operator=private?

class LoadLumScanner_v8002 : public ILoadLumScanner { 
public:
// default constructor
LoadLumScanner_v8002();

// copy constructor
LoadLumScanner_v8002(const LoadLumScanner_v8002& rhs);

// move constructor
LoadLumScanner_v8002(LoadLumScanner_v8002&& rhs);

// non-throwing copy-and-swap idiom unified assignment
inline LoadLumScanner_v8002& operator=(LoadLumScanner_v8002 rhs) {
    rhs.swap(*this);
    return *this;
}

// non-throwing-swap idiom
inline void swap(LoadLumScanner_v8002& rhs) throw() {
    // enable ADL (not necessary in our case, but good practice)
    using std::swap;
    // swap base members
    // ... 
    // swap members
    swap(mValidatedOk, rhs.mValidatedOk);
    swap(mFile, rhs.mFile);
    swap(mPartNo, rhs.mPartNo);
    swap(mMediaSequenceNo, rhs.mMediaSequenceNo);
    swap(mMaxMediaSequenceNo, rhs.mMaxMediaSequenceNo);
    swap(mLoadListOffset, rhs.mLoadListOffset);
    swap(mFirstLoadOffset, rhs.mFirstLoadOffset);
    swap(mLoadCount, rhs.mLoadCount);
    swap(mLoadIndex, rhs.mLoadIndex);
    swap(mLoadMediaSequenceNo, rhs.mLoadMediaSequenceNo);
    swap(mLoadPartNo, rhs.mLoadPartNo);
    swap(mLoadFilePath, rhs.mLoadFilePath);
}

// destructor
virtual ~LoadLumScanner_v8002();
}
like image 478
johnco3 Avatar asked May 06 '12 17:05

johnco3


People also ask

How can you prohibit a copy of an object from the same 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.

What is the difference between copy constructor and move constructor?

Move constructor moves the resources in the heap, i.e., unlike copy constructors which copy the data of the existing object and assigning it to the new object move constructor just makes the pointer of the declared object to point to the data of temporary object and nulls out the pointer of the temporary objects.

What is the difference between move constructor and move assignment?

The move assignment operator is different than a move constructor because a move assignment operator is called on an existing object, while a move constructor is called on an object created by the operation. Thereafter, the other object's data is no longer valid.


1 Answers

Both of the two solutions you mention work fine.

1.

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

The "= delete" signature is new with C++11 (as is the rvalue reference), and means essentially the same thing as the C++03 technique (declare private and don't define). The advantage of the C++11 solution is that it will for sure catch mistakes at compile time, not delay until link time.

Your compiler may not yet support "= delete" and in that case, you'll have to fall back on the first solution.

A third solution is to default the copy members:

class MoveOnly
{
public:
   MoveOnly(MoveOnly&&);
   MoveOnly& operator=(MoveOnly&&);
};

When a move special member is declared, whether defaulted or not, then the compiler will implicitly add deleted copy members if you do not declare them otherwise. Your compiler may or may not implement this feature yet.

like image 161
Howard Hinnant Avatar answered Oct 06 '22 01:10

Howard Hinnant