简介
就是一些类你不想让编译器生成默认的拷贝构造函数,目的是防止调用默认的拷贝构造出问题。
编译器生成的默认拷贝构造存在的隐患
// for_test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <boost/noncopyable.hpp>
class MyClass //: boost::noncopyable
{
public:
MyClass() { m_data = new char('Y'); }
~MyClass()
{
delete m_data;
}
private:
char * m_data;
};
int main()
{
{
MyClass classA;
MyClass classB(classA);
}
/* 执行到这的时候,出了花括号,classA的析构函数被调用,classB的析构函数也被调用
m_data被删除两次,就出错了。*/
std::cout << "Hello World!\n";
}
细心的小伙伴发现我没有定义拷贝赋值函数为啥赋值操作还能进行?实际上是编译器自动生成了。编译器也不是大聪明,只会进行简单的生成,对于结构复杂的类,如果我们没有定义合适的拷贝赋值或拷贝构造,就需要显示声明,后面的代码不能对该类的对象进行复制操作。
boost实现不可拷贝的方案
// for_test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <boost/noncopyable.hpp>
class MyClass : boost::noncopyable
{
public:
MyClass() { m_data = new char('Y'); }
~MyClass()
{
delete m_data;
}
private:
char * m_data;
};
int main()
{
{
MyClass classA;
MyClass classB(classA);
}
/// 执行到这的时候,出了花括号,classA的析构函数被调用,classB的析构函数也被调用
/// 成员m_data被删除两次,就出问题了。
std::cout << "Hello World!\n";
}
用法很简单,继承boost::noncopyable
类就行了。main里面的代码进行了复制,编译器就会报错:
严重性 代码 说明 项目 文件 行 禁止显示状态
错误(活动) E1776 无法引用 函数 “MyClass::MyClass(const MyClass &)” (已隐式声明) – 它是已删除的函数 for_test C:\Users\YK-067\source\repos\for_test\for_test.cpp 25
严重性 代码 说明 项目 文件 行 禁止显示状态
错误 C2280 “MyClass::MyClass(const MyClass &)”: 尝试引用已删除的函数 for_test C:\Users\YK-067\source\repos\for_test\for_test.cpp 25
boost源码
noncopyable.hpp
// Boost noncopyable.hpp header file --------------------------------------//
// (C) Copyright Beman Dawes 1999-2003. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See http://www.boost.org/libs/utility for documentation.
#ifndef BOOST_CORE_NONCOPYABLE_HPP
#define BOOST_CORE_NONCOPYABLE_HPP
#include <boost/config.hpp>
namespace boost {
// 私有的拷贝构造和拷贝赋值使得子类的不可被复制
namespace noncopyable_ // protection from unintended ADL。ADL 实参依赖查找(argument-dependent lookup), 允许调用其他命名空间中的函数。
{
#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 Traits 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
#endif // BOOST_CORE_NONCOPYABLE_HPP
总结
实际原理上很简单,就是父类把operator=
和 ()
成员函数定义成private的了。
目的也很直白,就是该类的对象别给我拷来拷去。