C++中使用复制构造函数确保深复制

C++中使用复制构造函数确保深复制

复制构造函数是一个重载的构造函数,由编写类的程序员提供。每当对象被复制时,编译器都将调用复制构造函数。

为 MyString 类声明复制构造函数的语法如下:

cpp 复制代码
class MyString
{
    MyString(const MyString& copySource); // copy constructor
};

MyString::MyString(const MyString& copySource)
{
    // Copy constructor implementation code
}

复制构造函数接受一个以引用方式传入的当前类的对象作为参数。这个参数是源对象的别名,您使用它来编写自定义的复制代码,确保对所有缓冲区进行深复制,如以下示例程序所示:

cpp 复制代码
#include <iostream>
#include <string.h>
using namespace std;

class MyString
{
private:
   char* buffer;

public:
   MyString() {}
   MyString(const char* initString) // constructor
   {
      buffer = NULL;
      cout << "Default constructor: creating new MyString" << endl;
      if(initString != NULL)
      {
         buffer = new char [strlen(initString) + 1];
         strcpy(buffer, initString);

         cout << "buffer points to: 0x" << hex;
         cout << (unsigned int*)buffer << endl;
      }
   }

   MyString(const MyString& copySource) // Copy constructor
   {
      buffer = NULL;
     cout << "Copy constructor: copying from MyString" << endl;
      if(copySource.buffer != NULL)
      {
         // allocate own buffer 
         buffer = new char [strlen(copySource.buffer) + 1];

         // deep copy from the source into local buffer
         strcpy(buffer, copySource.buffer);

         cout << "buffer points to: 0x" << hex;
         cout << (unsigned int*)buffer << endl;
      }
   }

   MyString operator+ (const MyString& addThis) 
   {
      MyString newString;

      if (addThis.buffer != NULL)
      {
         newString.buffer = new char[GetLength() + strlen(addThis.buffer) + 1];
         strcpy(newString.buffer, buffer);
         strcat(newString.buffer, addThis.buffer);
      }

      return newString;
   }

   // Destructor
   ~MyString()
   {
      cout << "Invoking destructor, clearing up" << endl;
      delete [] buffer;
   }

   int GetLength() 
   { return strlen(buffer); }

   const char* GetString()
   { return buffer; }
};

void UseMyString(MyString str)
{
   cout << "String buffer in MyString is " << str.GetLength();
   cout << " characters long" << endl;

   cout << "buffer contains: " << str.GetString() << endl;
   return;
}

int main()
{
   MyString sayHello("Hello from String Class");
   UseMyString(sayHello);

   return 0;
}

输出:

复制代码
Default constructor: creating new MyString
buffer points to: 0x01232D90
Copy constructor: copying from MyString
buffer points to: 0x01232DD8
String buffer in MyString is 17 characters long
buffer contains: Hello from String Class
Invoking destructor, clearing up
Invoking destructor, clearing up

分析:

大多数代码都与程序清单 9.8 类似,只是新增了一个复制构造函数(第 23~38 行)。首先,将重点放在 main( )上,它与以前一样创建了对象 sayHello,如第 65 行所示。创建 sayHello 导致了第 1 行输出,这是由 MyString 的构造函数的第 12 行生成的。出于方便考虑,这个构造函数还显示了 buffer 指向的内存地址。接下来, main( )将 sayHello 按值传递个函数 UseMyString( ),如第 66 行所示,这将自动调用复制构造函数,输出指出了这一点。复制构造函数的代码与构造函数很像,基本思想也相同:检查 copySource.buffer 包含的 C 风格字符串的长度(第 30 行),分配相应数量的内存并将返回的指针赋给 buffer,再使用 strcpy 将 copySource.buffer 的内容复制到 buffer(第 33 行)。这里并非浅复制(复制指针的值),而是深复制,即将指向的内容复制到给当前对象新分配的缓冲区中。

程序的输出表明,拷贝中的 buffer 指向的内存地址不同,即两个对象并未指向同一个动态分配的内存地址。因此,函数 UseMyString( )返回、形参 str 被销毁时,析构函数对复制构造函数分配的内存地址调用 delete[], 而没有影响 main( )中 sayHello 指向的内存。 因此, 这两个函数都执行完毕时,成功地销毁了各自的对象,没有导致应用程序崩溃。

该文章会更新,欢迎大家批评指正。

推荐一个零声学院的C++服务器开发课程,个人觉得老师讲得不错,

分享给大家:Linux,Nginx,ZeroMQ,MySQL,Redis,

fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,

TCP/IP,协程,DPDK等技术内容

点击立即学习:C/C++后台高级服务器课程

相关推荐
利刃大大1 小时前
【高并发内存池】五、页缓存的设计
c++·缓存·项目·内存池
C语言小火车2 小时前
【C++八股文】基础知识篇
c++·tcp/ip·const·智能指针·多线程同步·static关键字·c++内存模型
liulilittle2 小时前
IP校验和算法:从网络协议到SIMD深度优化
网络·c++·网络协议·tcp/ip·算法·ip·通信
眠りたいです2 小时前
基于脚手架微服务的视频点播系统-播放控制部分
c++·qt·ui·微服务·云原生·架构·播放器
Want5953 小时前
C/C++圣诞树①
c语言·开发语言·c++
老赵的博客3 小时前
c++ 杂记
开发语言·c++
jimmy.hua3 小时前
[C++刷怪笼]:set/map--优质且易操作的容器
开发语言·c++
tan180°3 小时前
Boost搜索引擎 网络库与前端(4)
linux·网络·c++·搜索引擎
bkspiderx4 小时前
C++经典的数据结构与算法之经典算法思想:贪心算法(Greedy)
数据结构·c++·算法·贪心算法
郝学胜-神的一滴4 小时前
避免使用非const全局变量:C++中的最佳实践 (C++ Core Guidelines)
开发语言·c++·程序人生