温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

从String类中看C++当中的深拷贝与浅拷贝解

发布时间:2020-07-24 03:27:42 来源:网络 阅读:941 作者:暮回_zz 栏目:编程语言

    了解过C++语言的人,都应该知道,C++语言中的构造函数,析构函数,拷贝构造函数,赋值运算符重载函数,如果不定义,编译器会自动生成的,当然,生成的只是一些最基本的,在达不到我们要求的条件下,就需要我们自己重新定义这些函数。

    我们现在说的讲的是深拷贝与浅拷贝,当然讨论这个问题的基础,一般情况下是我们定义的变量是以指针形式出现的,原因就在于,不论赋值还是拷贝,我们要实现两个指针指向的内容一致,那我得到新的指针和原指针是指向同一块内存空间还是两块内存空间的相同内容。如果是指向同一块空间,就存在了安全隐患,我们在自己管理空间时,就很有可能对一块空间进行了多次的释放,有些编译器下会报错,甚至直接奔溃,有些编译器虽不会抛出异常,但也会对后续的程序造成未知的错误。

 

那么,现在就以String为例,看看如何解决这些问题。

 

//参数列表中,pstr为char* 类型,s为String类型

//实现方法1:

class String
{
 friend ostream& operator<<(ostream& _out, const String& s);
public:
 String(const char* pstr) :_str(new char[strlen(pstr)+1])
 {
  strcpy(_str,pstr);
  cout << "构造" << endl;//做标识
 }
 String(const String& s) :_str(new char[strlen(s._str) + 1])
 {
  strcpy(_str,s._str);
  cout << "拷贝构造"<<endl;//做标识
 }
 String& operator = (const String& s)
 {
  if (this == &s)//不给自己赋值,防止对一块空间进行二次析构
  {
   char* tmp = (new char[strlen(s._str) + 1]);
   strcpy(tmp, s._str);
   delete[]_str;
   _str = tmp;
  }
  cout << "赋值重载" << endl;//做标识
  return *this;  //注意返回值
 }
 ~String()
 {
  if (this != NULL)
  {
   delete[]_str;
   _str = NULL;
  }
  cout << "析构" <<endl;//做标识
 }
private:
 char *_str;
};
//输出运算符重载
ostream& operator<<(ostream& _out,const String& s)
{
 _out << s._str<< endl;
 return _out;
}

 

//*****************************************************************************************

 

//String类的实现2

class String
{
 friend ostream& operator<<(ostream& _out, const String& s);
public:
 String(const char* str) :_str(new char[strlen(str)+1])//同上
 {
  strcpy(_str,str);
 }
 //拷贝构造
 String(const String& s) : _str(NULL)
 {
  String tmp(s._str);
  std::swap(_str,tmp._str);
 }
 //赋值运算符重载
 //String&operator=(const String& s)
 //{
 // if (this != &s)
 // {
 //  char* tmp(s._str);//用s._str或者s实例化tmp都可以
 //  std::swap(_str,tmp);
 // }
 // return *this;
 //}
 
 //赋值运算符重载之开辟空间法
 String&operator=(const String& s)
 {
  if (this != &s)
  {
   char* tmp = new char[strlen(s._str) + 1];
   strcpy(tmp,s._str);
   delete[]_str;
   _str = tmp;
  }
  return *this;
 }
 //析构
 ~String()
 {
  if (NULL == _str)
  {
   delete[] _str;
   _str = NULL;
  }
 }
private:
 char* _str;
};
//输出运算符重载
ostream& operator<<(ostream& _out,const String& s)
{
 _out << s._str<< endl;
 return _out;
}

 

// String类的实现3------>浅拷贝实现防止内存的多次释放

class String
{
 friend ostream& operator<<(ostream& _out, const String& s);
public:
 String(const char* pdata)
  :_str(new char[strlen(pdata)+1])
  , _count(new int)
 {
  strcpy(_str,pdata);
  *_count = 1;
 }
 String(const String& s)
  :_str(s._str)
  , _count(s._count)
 {
  _count++;
 }
 
 String& operator=(const String& s)
 {
  if (this != &s)
  {
   if (--(*_count) == 0)
   {
    delete[]_str;
    delete _count;
   }
   _count = s._count;
   _str = s._str;
   _count++;
  }
  return* this;
 }
 ~String()
 {
  if (--(*_count) == 0)
  {
   delete[] _str;
   delete _count;
  }
 }
private:
 char* _str;
 int* _count;
};
//输出运算符重载
ostream& operator<<(ostream& _out,const String& s)
{
 _out << s._str<< endl;
 return _out;
}

//*****************************************************************************************

友元函数受第一参数的限制,只能采用类外定义,引入友元

方法三,关于引入计数器,在面试过程中,这是最不推荐的方法,HR往往更倾向于让你写出深拷贝的方法。

 

深拷贝与浅拷贝是面试过程中经常出现的题目,弄清楚这类问题是非常必要的

 

 

 

 

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI