You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++拷贝赋值运算符成员删除/重置作用及版本正确性问询

class B;

class A
{
 private:
   list<B*> myList;
   unique_ptr<B> smartUniq;
   

 public:
   A()
   {
      myList.push_back(new B(5));
      myList.push_back(new B(6));
      myList.push_back(new B(7));
   }

   ~A()
   {
      for (auto& item : myList)
      {
         
         delete item;
      }
      cout << "destructor"<<endl;
   }

   
   //Copy constructor
   A(const A &src)
   {
     for (auto& item : src.myList)
     {
       myList.push_back(new B(item->getb()));
     }
     smartUniq(make_unique<B>(*src.smartUniq))
   }
 
   /////////////////////////  VERSION1: Copy assignement  
   A& operator= (const A &src)
   {
     for (auto& item : myList)
     {
       if (item != nullptr)
          delete item;
     }
     
     for (auto& item : src.myList)
     {
       myList.push_back(new B(item->getb()));
     }
     smartUniq(make_unique<B>(*src.smartUniq))

     return *this;
   }

   /////////////////////////  VERSION2: Copy assignement  
   A& operator= (const A &src)
   {
     if( this != &src)
     {
         for (auto& item : src.myList)
         {
            myList.push_back(new B(item->getb()));
         }
         smartUniq.reset(src.smartUniq.get() ? make_unique<B>(*src.smartUniq) : nullptr);
     }

     return *this;
   }
};
问题

Q1:下述两个拷贝赋值运算符版本(Version1、Version2或其他)哪个正确?

  • 拷贝前删除当前成员的作用是什么?
  • 代码中if( this != &src)的作用是什么?

Q2:smartUniq.reset的作用是什么?是否可以像Version1那样不使用该方法?


回答

Q1 分析

哪个版本正确?

两个版本都不正确,各自存在严重问题:

  • Version1的问题:
    1. 删除myList元素后没有清空列表,导致列表里全是野指针,后续析构函数会重复delete这些野指针,触发未定义行为;
    2. smartUniq(make_unique<B>(*src.smartUniq))是语法错误,unique_ptr不能直接这么调用构造赋值;
    3. 未处理src.smartUniq为空的情况,直接解引用会触发空指针访问。
  • Version2的问题:
    1. 没有先释放当前myList的已有元素,直接push_back新元素,导致原有内存完全泄漏;
    2. 即使加了自赋值判断,正常赋值场景下的内存泄漏问题依然存在。

正确的拷贝赋值应该先完全清理当前对象的资源(delete所有myList元素并清空列表),再拷贝源对象的资源,同时处理自赋值和异常安全(比如用copy-and-swap惯用法)。

拷贝前删除当前成员的作用

释放当前对象已经占用的动态内存,避免内存泄漏。如果不删除原有成员就直接添加新内容,原来在堆上分配的B对象会因为失去指针引用而无法被释放,最终造成内存泄漏。

if( this != &src)的作用

防止自赋值(比如执行a = a;这种操作)。如果没有这个判断,自赋值时会先删除当前对象的资源,之后再从已被销毁的资源里拷贝,导致访问野指针,触发未定义行为。


Q2 分析

smartUniq.reset的作用

unique_ptr::reset()有两个核心功能:

  1. 释放当前unique_ptr指向的对象(如果当前有指向的对象);
  2. 将unique_ptr重新指向传入的新对象(如果传入了参数),如果不传参数就把unique_ptr置为空。
    Version2里的写法还处理了src.smartUniq为空的情况,避免空指针解引用。

是否可以像Version1那样不使用reset?

可以,但要修正Version1里的错误写法:

  • Version1里的smartUniq(make_unique<B>(*src.smartUniq))是语法错误,正确的写法应该用赋值操作:smartUniq = make_unique<B>(*src.smartUniq);
  • 但要注意,这种写法需要先判断src.smartUniq是否为空,否则直接解引用空指针会触发未定义行为,比如:
    if (src.smartUniq) {
        smartUniq = make_unique<B>(*src.smartUniq);
    } else {
        smartUniq.reset(); // 等价于smartUniq = nullptr;
    }
    

unique_ptr的赋值运算符会自动释放原有对象,所以效果和用reset()类似,但reset()的写法在处理空指针场景时更简洁直观。


内容的提问来源于stack exchange,提问作者Ghazi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 22:14:51