🎐在处理向运输层添加数据报时, 定义了一个结构体, 结构体中包含一个byte类型的指针data, 用来存储数据存放的地址, 另外还有一个uint32_t类型的size用来存放数据占用的字节数, 结构体按照8字节对齐, 无论如何调整size和data两个成员的位置, 也都有4个字节无法使用. 这4个字节用不了, 重新定义size的类型为size_t, 为了方便拼接协议的各个部分, 重载了结构体的+运算.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 typedef  struct  Data  {    size_t  size;     byte *data;          Data () {         size = 0 ;         data = nullptr ;     }          ~Data () {         printf ("free! \n" );         if  (size > 0  && data != nullptr ) {             delete  [] data;             data = nullptr ;             size = 0 ;         }     }          struct  Data  operator +(struct  Data & other) {         struct  Data  result;         result.size = size + other.size;         result.data = new  byte[result.size];         memcpy (result.data, data, size);         memcpy (result.data + size, other.data, other.size);         return  result;     }      } Data; 
结构体里面的data存储的是堆中存放数据的地址, 重载+运算符会生成一个新的对象, 这就涉及到内存管理了, 如果执行a + b + c这样的运算, 其中相加过程中会生成两个结构体变量, 至少有一个属于临时变量, 运算结束后就会释放, 因此必须在析构函数中释放data所指向区域的内存. 上面的代码看上去没有问题.
尝试运行下面👇的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 Data test (Data & a)   {    Data b = a;     Data c = a + a;     Data d = c + a;     Data e = b + d;     return  e; } int  main (int  argc, const  char  * argv[])           Data m;     m.size = 3 ;     m.data = new  byte[3 ];          Data n;     n.size = 4 ;     n.data = new  byte[4 ];          Data l = m + n;          Data t = test (l);          sleep (10 );          return  0 ; } 
程序会报一个错误
1 2 malloc: *** error for  object 0x10072d520: pointer being freed was not allocated malloc: *** set  a breakpoint in  malloc_error_break to debug 
大致的意识就是free释放的区域不是malloc申请的, 在这个例子中也就是delete了不属于new申请的区域. 仔细检查了一下代码, 并没有这种情况. 那为什么会出现这种情况呢? 添加断点后发现, 对同一个地址调用了两次delete, 所以自然会报这种错误. 在test函数中, 临时变量b离开作用域以后调用了一次析构函数, 这里b被赋值成了a, test函数中声明的参数是左值引用, test调用前没有拷贝参数到形参, 这里没问题, 问题在于对b复制时, 可能只是浅拷贝, 也就是只对对应的成员变量赋值, 两个data指向同一个区域. 因此需要重写拷贝函数和拷贝构造函数, 拷贝构造函数一般是变量声明的同时赋值使用, 拷贝函数则是拷贝到已有变量. 拷贝函数般重载运算符=, 拷贝构造函数有两种常见的形式:
1 2 3 4 5 6 Data b; Data a = b; Data a (b)  ;
添加拷贝构造函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 typedef  struct  Data  {    size_t  size;     byte *data;          Data () {         size = 0 ;         data = nullptr ;     }          ~Data () {         printf ("free! \n" );         if  (size > 0  && data != nullptr ) {             delete  [] data;             data = nullptr ;             size = 0 ;         }     }          Data (struct  Data & other) {         if  (other.size > 0  && other.data != nullptr ) {             size = other.size;             data = new  byte[size];             memcpy (data, other.data, size);         } else  {             size = 0 ;             data = nullptr ;         }     }          struct  Data  & operator =(struct  Data & other) {         if  (this  == &other) {             return  *this ;         }         if  (other.size != 0  && other.data != nullptr ) {             if  (size != 0  && data != nullptr ) {                 delete  [] data;             }             size = other.size;             data = new  byte[size];             memcpy (data, other.data, size);         }         return  *this ;     }          struct  Data  operator +(struct  Data & other) {         struct  Data  result;         result.size = size + other.size;         result.data = new  byte[result.size];         memcpy (result.data, data, size);         memcpy (result.data + size, other.data, other.size);         return  result;     }      } Data; 
利用Xcode提供的工具检查一下有没有内存泄漏
打开菜单栏Product->Profile即可. 快捷键是⌘ + I