1. 说明
在上一篇的示例中在说明封装抽象类时有用到boost::noncopyable类,在实际使用的很多情况下,加没加这个类似乎对我的操作没有影响,那么这个类到底有什么作用呢,在这篇笔记中详细分析一下。
1.1 noncopyable作用
其官方说明是:Private copy constructor and copy assignment ensure classes derived from class noncopyable cannot be copied.大意是将私有化类的拷贝构造函数和拷贝赋值操作符,这样子类可以调用,但是外部调用者不能通过复制/赋值等语句来产生一个新的对象。
boost::noncopyable主要的用法是作为父类供其他类继承其特性。
2. 示例
这里定义了两个类Test1和Test2,其中Test2继承boost::noncopyable的特性
#include <iostream>
#include <boost/noncopyable.hpp>
class Test1 {
public:
Test1(int i) {std::cout << "This is Test1 that is copyable" << std::endl;}
};
class Test2 : boost::noncopyable {
public:
Test2(int i) {std::cout << "This is Test2 that is noncopyable" << std::endl;}
};
int main()
{
Test1 t1(1);
Test2 t2(2);
Test1 t3 = t1; // It's OK
Test1 t4(t1); // It's OK
Test2 t5 = t2; // Cannot be referenced
Test2 t6(t2); // Cannot be referenced
Test2 &t7 = t2; // It's OK
return 0;
}
直接编译时会报错,如下:
g++ test.cpp
test.cpp: In function ‘int main()’:
test.cpp:23:16: error: use of deleted function ‘Test2::Test2(const Test2&)’
23 | Test2 t5 = t2; // Cannot be referenced
| ^~
test.cpp:10:7: note: ‘Test2::Test2(const Test2&)’ is implicitly deleted because the default definition would be ill-formed:
10 | class Test2 : boost::noncopyable {
| ^~~~~
test.cpp:10:7: error: use of deleted function ‘boost::noncopyable_::noncopyable::noncopyable(const boost::noncopyable_::noncopyable&)’
In file included from /usr/local/include/boost/noncopyable.hpp:15,
from test.cpp:3:
/usr/local/include/boost/core/noncopyable.hpp:49:7: note: declared here
49 | noncopyable( const noncopyable& ) = delete;
| ^~~~~~~~~~~
test.cpp:24:16: error: use of deleted function ‘Test2::Test2(const Test2&)’
24 | Test2 t6(t2); // Cannot be referenced
从编译信息可以看出,Test2不支持使用复制的方式来实例化类。
3. boost::noncopyable类详解
boost::noncopyable定义在 <boost/core/noncopyable.hpp> 中。定义如下:
namespace boost {
// Private copy constructor and copy assignment ensure classes derived from
// class noncopyable cannot be copied.
// Contributed by Dave Abrahams
namespace noncopyable_ // protection from unintended ADL
{
#ifndef BOOST_NONCOPYABLE_BASE_TOKEN_DEFINED
#define BOOST_NONCOPYABLE_BASE_TOKEN_DEFINED
// noncopyable derives from base_token to enable Type Traits to detect
// whether a type derives from noncopyable without needing the definition
// of noncopyable itself.
//
// The definition of base_token is macro-guarded so that Type Trais can
// define it locally without including this header, to avoid a dependency
// on Core.
struct base_token {};
#endif // #ifndef BOOST_NONCOPYABLE_BASE_TOKEN_DEFINED
class noncopyable: base_token
{
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: // emphasize the following members are private
noncopyable( const noncopyable& );
noncopyable& operator=( const noncopyable& );
#endif
};
}
typedef noncopyable_::noncopyable noncopyable;
} // namespace boost
注意其中的关键语句:
#if !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS)
noncopyable( const noncopyable& ) = delete;
noncopyable& operator=( const noncopyable& ) = delete;
#else
private: // emphasize the following members are private
noncopyable( const noncopyable& );
noncopyable& operator=( const noncopyable& );
#endif
BOOST_NO_CXX11_DELETED_FUNCTIONS
类重载了复制和"=“运算符,将它们变为"delete”。上面的语句中如果没有定义BOOST_NO_CXX11_DELETED_FUNCTIONS
类,那么直接实现了重载运算符的功能,如果有定义,则将这两个运算符变成私有成员。即无论如何,noncopyable类下复制和"="运算符都被重载为"delete"了。
参考资料
https://www.boost.org/doc/libs/1_78_0/libs/core/doc/html/core/noncopyable.html