未使用swap的C++拷贝赋值运算符失效场景及内存泄漏疑问
关于HasPtr类的拷贝赋值运算符问题解答
一、*ps = *(h.ps);语句失效的场景
这条语句执行时会触发未定义行为(即“失效”)的核心场景是当前对象的ps指针处于无效状态,常见情况包括:
对象已被析构,
ps成为野指针
示例代码:HasPtr* ptr = new HasPtr("original"); delete ptr; // 对象析构后,ps指向的内存已被释放,ptr变为野指针 HasPtr other("new"); *ptr = other; // 访问野指针指向的内存,执行*ps = *(other.ps)会触发非法内存访问,导致崩溃或随机异常ps被手动置为空指针(虽类接口未提供此操作,但通过非常规手段修改private成员时)
示例代码(仅用于演示,实际开发禁止此类操作):HasPtr obj("test"); // 强制修改private成员,将ps置空 std::string*& ps_ref = const_cast<std::string*&>(obj.ps); ps_ref = nullptr; HasPtr other("hello"); obj = other; // 访问空指针,执行*ps = ...会触发空指针引用错误
注:自赋值(obj = obj;)不会导致这条语句失效,因为*ps = *ps是合法的字符串自赋值操作,但这种操作本身无意义,且在更复杂的赋值实现中可能引发问题。
二、关于内存泄漏的疑问
你提到的“内存泄漏”说法并不准确,正常合规使用该类时不会出现内存泄漏:
- 每个
HasPtr对象的构造函数都会通过new分配独立的std::string内存,析构函数通过delete释放该内存; - 拷贝构造函数为新对象分配新内存,保证每个对象拥有独立的内存资源;
- 赋值运算符仅修改现有内存中的字符串内容,不会分配新内存,原有内存仍会在对象析构时被释放。
如果GPT提到内存泄漏,大概率是混淆了其他场景:
- 若修改赋值运算符为直接重新分配内存(比如
ps = new std::string(*h.ps);)且未释放原有内存,才会导致泄漏; - 若用户手动篡改
ps指针(比如将其指向其他内存或重复释放),可能引发内存问题,但这属于不合规使用,并非类本身的设计缺陷。
这个类真正的问题是不具备异常安全性:当*ps = *(h.ps);执行时,如果std::string的赋值运算符抛出异常(比如内存分配失败),对象的i成员还未被修改,会导致对象处于“部分修改”的不一致状态——这正是copy-and-swap惯用法要解决的核心问题之一。
内容的提问来源于stack exchange,提问作者paul m
相关产品推荐
相关产品推荐

