自定义智能指针移动操作异常:无构造/析构输出问题排查求助
问题排查:移动语义导致智能指针未正确触发构造/析构打印
这段代码执行后未输出A类的构造与析构打印内容,与预期不符。移除移动操作后运行正常,推测移动操作实现存在问题,以下是排查结果和修复方案:
原代码
#include <iostream> #include <thread> #include <mutex> #include <condition_variable> using namespace std; template <class T> class smart{ public: smart():pt{nullptr}{ } smart(T *ptr):pt{ptr}{ } T *pt; smart(const smart& ob)=delete; smart operator=(const smart& ob)=delete; smart (smart&& dyingob){ this->pt=dyingob.pt; dyingob.pt=nullptr; } void operator=(smart&& dyingob){ pt=dyingob.pt; dyingob.pt=nullptr; } T* operator ->(){return this->pt;}; ~smart(){ if(pt!=nullptr) delete pt; } }; class A{ public: A(int n){ data=n; cout<<"\nconstructed"; } ~A(){ cout<<"\ndestructed"; } int data; }; int main() { smart<A> ob(new A(5)); smart<A> ob1; ob1=(std::move(ob)); cout<<ob->data; return 1; }
问题根源
- 空指针访问触发未定义行为:执行
ob1 = std::move(ob);后,ob的pt被置为nullptr,此时cout<<ob->data;相当于访问空指针,程序可能直接崩溃,导致构造/析构的打印内容被中断或无法输出。 - 移动赋值运算符内存泄漏风险:如果当前对象(如
ob1)原本持有非空指针,移动赋值时直接覆盖pt会导致原有资源无法释放,造成内存泄漏。
修复方案
1. 修复移动赋值运算符
先释放当前对象持有的资源,再接管移动源的指针:
void operator=(smart&& dyingob){ // 先释放当前资源,避免内存泄漏 if (pt != nullptr) { delete pt; } pt = dyingob.pt; dyingob.pt = nullptr; }
2. 移除空指针访问
将main函数中对ob的访问改为访问ob1(移动后资源已转移到ob1):
int main() { smart<A> ob(new A(5)); smart<A> ob1; ob1 = std::move(ob); // 访问ob1的资源,ob已处于空状态 cout << "\nData: " << ob1->data; return 0; }
3. 可选优化:添加noexcept
给移动构造和移动赋值运算符加上noexcept,帮助标准库容器优化性能:
smart (smart&& dyingob) noexcept { this->pt = dyingob.pt; dyingob.pt = nullptr; } void operator=(smart&& dyingob) noexcept { if (pt != nullptr) { delete pt; } pt = dyingob.pt; dyingob.pt = nullptr; }
修复后运行结果
执行修改后的代码会输出:
constructed Data: 5 destructed
内容的提问来源于stack exchange,提问作者Tej Ravi
相关产品推荐
相关产品推荐

