阻止拷贝

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/github_39286601/article/details/77776553

大多数类应该定义默认构造函数、拷贝构造函数和拷贝赋值运算符、无论是隐式还是显式。
但对于某些类来说这些操作并无意义,在此种情况下,定义时必须采用某种机制阻止赋值或拷贝。
(1)定义删除的函数
在函数的参数列表后面加上=delete来指明希望将其定义为删除的。

struct NoCopy {
      NoCopy()=default;  //使用合成的默认构造函数
      NoCopy(const NoCopy&)=delete;   //阻止拷贝
      NoCopy &operator=(const NoCopy &)=delete;  //阻止赋值
      ~NoCopy()=default;   //使用合成的析构函数
      };
  =delete 必须出现函数第一次声明的时候,这和=default不同

与=default 的另一个不同之处是,我们可以对任何函数指定=delete(我们只对编译器可以合成的默认构造函数和拷贝控制成员使用=default)。
析构函数不能是删除的成员
我们不能删除析构函数。对于删除了析构函数的类型,我们不能定义该类型的变量或成员,但可以动态分配这种类型的对象。但是这些对象不可以释放。

struct NoDtor{
    NoDtor()=default;
    ~NoDtor()=delete;
};
NoDtor nd;  //error:析构函数被删除
NoDtor *p=new NoDtor();   //正确:但不可delete p;
delete p;

合成的拷贝控制成员可能是删除的
如果一个类有数据成员不能默认构造、拷贝、复制或销毁,则对应的成员函数将被定义为删除。
对于具有引用成员或无法默认构造的const成员的类,编译器不会为他们合成默认构造函数
如果一个类有const成员,则它不能使用合成的拷贝赋值运算符。毕竟,此运算符试图赋值所有成员,而将一个新值赋予一个const对象是不可能的。
对于有引用成员的类,合成构造赋值运算符被定义为删除的。

(2)private拷贝控制

class PrivateCopy{
/*拷贝控制成员为private,则普通用户不可访问*/
     PrivateCopy(PrivateCopy &);
     PrivateCopy &operator=(PrivateCopy &);
public:
    PrivateCopy()=default;
    ~PrivateCopy();
};

友元和成员函数仍可拷贝对象,为了阻止其拷贝,我们将这些拷贝声明为private的,但并不定义他们。

C++ 11标准,希望使用=delete来阻止拷贝,而非声明为private的


行为像值的类
类的行为像一个值,有着自己的状态,对于拷贝一个像值的对象时,副本和原对象是独立的,改变副本的值不会改变原对象的值。

类值的行为,对于类管理的资源,每个对象都应有一份自己的拷贝。ex

定义一个HasPtr类,让他的行为像一个值
(1)定义一个拷贝构造函数,完成string的拷贝
(2)定义析构函数来释放string3)定义一个拷贝赋值构造函数来释放当前的string,并从右侧对象拷贝string
class HasPtr{
  public:
      HasPtr(const std::string &s=std::string()):ps(new std::string(s)),i(0) {} 

      //对ps指向的string,每个HasPtr对象都有自己的拷贝
      HasPtr(const HasPtr &p):ps(new std::string(*p.ps)),i(p.i){}  
      HasPtr & operator=(const HasPtr &);
      ~HasPtr(){delete ps;}
  private:
      std::string *ps;
      int i;
};
HasPtr & HasPtr::operator=(const HasPtr &rhs)
{
  auto newp=new string(*rhs.ps);    //拷贝底层string
  delete ps;                     //释放旧内存
  ps=newp;                        //从右侧运算对象拷贝数据到本对象
  i=rhs.i;
  return *this;                    //返回本对象
}

定义行为像指针的类
行为像一个指针的类共享状态,当我们拷贝一个像指针的对象时,原对象和副本是共享底层数据,改变副本也会改变原对象。
引入计数机制,进行直接管理资源,最好的方法当然是使用share_ptr来进行实现类似行为指针的类。

为类定义拷贝构造函数和拷贝赋值函数,来拷贝指针成员本身而非它指向的string
class HasPtr{
   public:
   //构造函数分配新的string和计数器,并将计数器置为1。
   HasPtr(const std::string &=std::string()):ps(new string(s),i(0),use(new std::size_t(1)){}
   //拷贝构造函数拷贝所有的三个数据成员,并递增计数器。
   HasPtr(const HasPtr &p):ps(p.ps),i(p.i),use(p.use){++*use;}
   HasPtr & operator=(const HasPtr&);
   ~HasPtr();
   private:
   std::string *ps;
   int i;
   std::size_t *use;
};
HasPtr& HasPtr::operator=(const HasPtr & rhs)
{
  ++*rhs.use;
  //旧内存的释放
  if(--*use==0)
  {
     delete ps;
     delete use;
  }

  ps=rhs.ps;
  i=rhs.i;
  use=rhs.use;
  return *this;
}
HasPtr::~HasPtr()
{
   if(--*use==0){
     delete ps;
     delete use;
   }
}

猜你喜欢

转载自blog.csdn.net/github_39286601/article/details/77776553