C++赋值运算符对指针成员的处理

对于赋值运算符重载函数,如果类的数据成员中含有指针,有时会导致灾难性的后果。对于指针间的赋值(注意这里指的是指针所指内容间的赋值,这里假设用_p给p赋值),先要将p所指向的空间delete掉(为什么要这么做呢?因为指针p所指的空间通常是new来的,如果在为p重新分配空间前没有将p原来的空间delete掉,会造成内存泄露),然后再为p重新分配空间,将_p所指的内容拷贝到p所指的空间。
我这里有些不明白,为啥不直接把_p指向的内容直接赋值给 p 指向的内存,即 *p = *_p,直接覆盖就不用把 p 删了重开分配空间,这样不是更方便吗?
举个例子:
test.h :

#include <iostream>
#include <string>
using namespace std;

class Pen{
private:
    int* length;
public:
    Pen(int length);
    Pen(const Pen& p);
    ~Pen();
    Pen& operator=(const Pen& p);
};

test.cpp :


#include "operator_assignment_test.h"

Pen::Pen(int length) {
    this->length = new int(length);
}

Pen::~Pen() {
    cout << "~Pen" << endl;
    if(length != nullptr)
    {
        delete length;
        length = nullptr;
    }
}

Pen::Pen(const Pen &p) {
//    length = p.length;// 这是默认拷贝函数的操作,会导致同一内存重复释放,造成重析构
    length = new int(*p.length);
    cout <<"copy constructor" << endl;
}

Pen &Pen::operator=(const Pen &p) { //传递参数是引用是为了减少拷贝开销,返回类型是引用是为了可链式赋值,如 a = b = c;

//     致命的实现方式一: 这是编译器默认提供的赋值重载,显然会造成重析构和内存泄漏
//    this->length = p.length;
//    return *this;

    if(this == &p) //防止自赋值陷入死循环
    {
        return *this;
    }

    // 这里非常疑惑,这里直接覆盖掉this->length指针指向的内存不更方便吗??然后直接 return *this:
//    *this->length = *p.length;

    // 正确的赋值操作方式:
    if(this->length != nullptr) //释放原来指向的内存,防止内存泄漏
    {
        delete this->length;
        this->length = nullptr;
    }
    this->length = new int(*p.length); //在堆中开辟新的空间,防止重析构

    return *this;
}

实在不知道为啥不可以直接覆盖呀!请读者不吝赐教!!万分感谢!~

img

为啥不直接把_p指向的内容直接赋值给 p 指向的内存,即 * p = * _p,直接覆盖就不用把 p 删了重开分配空间,这样不是更方便吗?
===主要是两个问题,一是两块内存的大小可能不一致,比如_p分配的空间更大,复制给p时,p的空间不够;二是你的写法不对,* p = * _p是将第一个字节进行了复制,不是内存空间复制。内存空间复制可以用memcpy函数。前提必须保证p的空间大小足够

不覆盖是因为如果覆盖,两个对象将同时指向一个内存,那么在其中一个被释放后,另外一个释放将会出错。