Introduction
There are times where an object should never be passed by copy but by reference or pointer. For instance, the class has a data member (like counter or mutex) which should not be duplicated. In this tip, we take a look at 2 techniques which declare the class to be non-copyable without resorting to using Boost's Noncopyable class.
Use delete Keyword
Delete the copy constructor and assignment operator. This works for C++11 and above.
class DeletedCopyFunc
{
public:
DeletedCopyFunc(int value): m_Value(value) {}
public:
DeletedCopyFunc(const DeletedCopyFunc&) = delete;
DeletedCopyFunc& operator=(const DeletedCopyFunc&) = delete;
private:
int m_Value;
std::mutex m_Mutex;
};
Make private
Declaring the copy constructor and assignment operator private
is another way and it is perfectly fine not to define their bodies. This technique works for all C++ versions.
class PrivateCopyFunc
{
public:
PrivateCopyFunc(int value) : m_Value(value) {}
private:
PrivateCopyFunc(const PrivateCopyFunc&);
PrivateCopyFunc& operator=(const PrivateCopyFunc&);
private:
int m_Value;
std::mutex m_Mutex;
};
How Boost Does It?
It can be seen from the Boost noncopyable source that it also uses the same techniques.
class noncopyable
{
protected:
#if !defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) &&
!defined(BOOST_NO_CXX11_NON_PUBLIC_DEFAULTED_FUNCTIONS)
BOOST_CONSTEXPR noncopyable() = default;
~noncopyable() = default;
#else
noncopyable() {}
~noncopyable() {}
#endif
#if !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS)
noncopyable( const noncopyable& ) = delete;
noncopyable& operator=( const noncopyable& ) = delete;
#else
private: noncopyable( const noncopyable& );
noncopyable& operator=( const noncopyable& );
#endif
};
Bonus: When copy Constructor and Assignment Operator are Called
Having done interviews over the years, I discover to my dismay that many job candidates are not aware of when copy constructor and assignment operator are called. Run the code below to see which lines are printed.
class CopyableClass
{
public:
CopyableClass(int value) : m_Value(value) {}
CopyableClass(const CopyableClass& that)
{
std::cout << "CopyableClass Copy Constructor called!" << std::endl;
this->m_Value = that.m_Value;
}
CopyableClass& operator=(const CopyableClass& that)
{
std::cout << "CopyableClass Assignment Operator called!" << std::endl;
this->m_Value = that.m_Value;
return *this;
}
private:
int m_Value;
};
int main()
{
CopyableClass a(10);
CopyableClass b = a; b = a;
CopyableClass c(a);
return 0;
}
The example code is hosted at Github.