单链表清空中为啥最后要把头结点的指针域置空?

清空单链表

Status ClearList(LinkList &L){
    Lnode *p,*q;
    p = L->next;
    while(p){
        q=p->next;
        delete p;
        p=q;
    }
    L->next = NULL; //头结点指针域为空
    return OK;
}

L->next = NULL; //头结点指针域为空

为什么要有这步?

这个操作是必要的,因为它是用来将头结点的指针域置为空,表示链表已经清空了。如果不写这个操作,那么头结点的指针域仍然会指向原来的第一个结点,即使这个结点已经被删除了。这样就会造成一个悬空指针(dangling pointer),也就是指向一个不存在或者无效的内存地址的指针。悬空指针是一种常见的编程错误,它可能会导致程序崩溃或者数据损坏。

所以,在while循环里面的delete p操作只是删除了链表中的每个结点,但没有改变头结点的指针域。需要在循环结束后再写一次 L->next = NULL 来确保头结点的指针域为空,这样才能完全清空链表。

p = L->next; delete p;这两步操作不是已经可以替代L->next= NULL吗?

这两步操作不能替代 L->next = NULL。因为 delete p 只是释放了 p 指向的内存空间,但没有改变 p 的值。p 仍然是一个指针,它还是会指向原来的内存地址,只是这个地址已经不属于你的程序了。如果你再次使用 p,就可能会发生未定义的行为(undefined behavior),比如访问到其他程序的数据或者触发系统异常。

L->next = NULL 是用来将 L 的指针域(也就是 p)置为空,表示它不再指向任何有效的内存地址。这样就避免了悬空指针的问题,也方便了后续的操作,比如判断链表是否为空或者重新分配内存。

可以借此理解 delete 和 NULL 的区别

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Qt智能指针--QScopedPointer ⽂章⽬录 概述 前⼀篇⽂章我们详细的介绍了的⽤法,那么,这⾥继续总结Qt的另⼀个智能指针QScopedPointer的⽤法。 QScopedPointer和C++的智能指针std::unique_ptr其概念是⼀样的,它包装了new操作符在堆上分配的动态对象,能够保证动态创建 的对象在任何时候都可以被正确地删除。但它有更严格的所有权,并且不能转让,⼀旦获取了对象的管理权,你就⽆法再从它那⾥取回来。 也就是说,只要出了作⽤域,指针就会被⾃动删除,因为它的拷贝构造和赋值操作都是私有的,与QObject及其派⽣类风格相同。 QScopedPointer ⾸先我们来看⼀个官⽅⽰例: 没有使⽤智能指针: void myFunction(bool useSubClass) { MyClass *p = useSubClass ? new MyClass() : new MySubClass; QIODevice *device = handsOverOwnership(); if (m_value > 3) { delete p; delete device; return; } try { process(device); } catch (...) { delete p; delete device; throw; } delete p; delete device; } 上⾯的写法,稍有不慎就会导致内存泄露,但是如果使⽤智能指针,就会变得很简单了: void myFunction(bool useSubClass) { QScopedPointer<MyClass> p(useSubClass ? new MyClass() : new MySubClass); QScopedPointer<QIODevice> device(handsOverOwnership()); if (m_value > 3) return; process(device); } 注意:因为拷贝构造和赋值操作私有的,所以不能⽤作容器的元素。 const 限制 C ++指针的const限定也可以⽤QScopedPointer表⽰: const QWidget *const p = new QWidget(); // 等同于: const QScopedPointer<const QWidget> p(new QWidget()); QWidget *const p = new QWidget(); // 等同于: const QScopedPointer<QWidget> p(new QWidget()); const QWidget *p = new QWidget(); // 等同于: QScopedPointer<const QWidget> p(new QWidget()); 考虑⼀种情况 上⾯说到,使⽤QScopedPointer智能指针动态创建的对象,⼀旦出了作⽤域就会 被⾃动释放并置,那么如果需要函数返回值怎么办 呢? ⽐如下⾯这种情况: QLabel * createLabel() { QScopedPointer<QLabel> pLabel(new QLabel()); // return pLabel.data(); //invalid return pLabel.take(); //valid } int main(int argc, char *argv[]) { QApplication a(argc, argv); QScopedPointer<QLabel> p1(createLabel()); p1->setText("hello"); p1->show(); return a.exec(); } 注意,我们在createLabel()函数创建label对象并返回时,不能使⽤data(),⽽要使⽤take(); 因为 T *QScopedPointer::data() const返回指向对象的常量指针,QScopedPointer仍拥有对象所有权。 所以通过data()返回过后就被 ⾃动删除了,从⽽导致mian函数的p1变成了野指针,程序崩溃。 ⽽使⽤T *QScopedPointer::take()也是返回对象指针,但QScopedPointer不再拥有对象所有权,⽽是转移到调⽤这个函数的caller,同 时QScopePointer对象指针置为NULL。 另外还有⼀个函数要注意。 void QScopedPointer::reset(T *other = Q_NULLPTR):delete⽬前指向的对象,调⽤其析构函数,将指针指向另⼀个对象other,所有 权转移到
C++智能指针的原理和实现 智能指针的原理和实现 ⼀、智能指针起因 ⼀、智能指针起因   在C++,动态内存的管理是由程序员⾃⼰申请和释放的,⽤⼀对运算符完成:new和delete。   new:在动态内存为对象分配⼀块间并返回⼀个指向该对象的指针;   delete:指向⼀个动态独享的指针,销毁对象,并释放与之关联的内存。   使⽤堆内存是⾮常频繁的操作,容易造成堆内存泄露、⼆次释放等问题,为了更加容易和更加安全的使⽤动态内存,C++11引⼊了智 能指针的概念,⽅便管理堆内存,使得⾃动、异常安全的对象⽣存期管理可⾏。智能指针主要思想是RAII思想,"使⽤对象管理资源",在类 的构造函数获取资源,在类的析构函数释放资源。智能指针的⾏为类似常规指针,重要的区别是它负责⾃动释放所指向的对象。   RAII是Resource Acquisition Is Initialization的简称,即资源获取就是初始化:   1.定义⼀个类来封装资源的分配与释放;   2.构造函数完成资源的分配及初始化;   3.析构函数完成资源的清理,可以保证资源的正确初始化和释放;   4.如果对象是⽤声明的⽅式在栈上创建局部对象,那么RAII机制就会正常⼯作,当离开作⽤域对象会⾃动销毁⽽调⽤析构函数释放资 源。 ⼆、智能指针类型 ⼆、智能指针类型   智能指针在C++11版本之后提供,包含在头⽂件<memory>,标准命名std间下,有auto_ptr、shared_ptr、weak_ptr、unique_ptr四 种,其auto_ptr已被弃⽤。   :拥有严格对象所有权语义的智能指针;   :拥有共享对象所有权语义的智能指针;   :到 shared_ptr 所管理对象的弱引⽤;   :拥有独有对象所有权语义的智能指针。 2.1 auto_ptr   auto_ptr是通过由 new 表达式获得的对象,并在auto_ptr⾃⾝被销毁时删除该对象的智能指针,它可⽤于为动态分配的对象提供异常安 全、传递动态分配对象的所有权给函数和从函数返回动态分配的对象,是⼀个轻量级的智能指针,适合⽤来管理⽣命周期⽐较短或者不会被 远距离传递的动态对象,最好是局限于某个函数内部或者是某个类的内部。   声明:   template< class T > class auto_ptr;   template<> class auto_ptr<void>; // 对类型void特化     成员函数:   (1) : 获得内部对象的指针;   (2) :释放被管理对象的所有权,将内部指针置为,返回内部对象的指针,此指针需要⼿动释放;   (3) :销毁内部对象并接受新的对象的所有权;   (4) :从另⼀auto_ptr转移所有权;   (5) 和:访问被管理对象。   注意事项:   (1) 其构造函数被声明为explicit,因此不能使⽤赋值运算符对其赋值,即不能使⽤类似这样的形式 auto_ptr<int> p = new int;   (2) auto_ptr 的对象所有权是独占性的,使⽤拷贝构造和赋值操作符时,会造成对象所有权的转移,被拷贝对象在拷贝过程被修改;   (3) 基于第⼆条,因此不能将auto_ptr放⼊到标准容器或作为容器的成员;   (4) auto_ptr不能指向数组,释放时⽆法确定是数组指针还是普通指针;   (5) 不能把⼀个原⽣指针交给两个智能指针对象管理,对其它智能指针也是如此。   auto_ptr是最早期的智能指针,在C++11 已被弃⽤,C++17 移除,建议使⽤unique_ptr代替auto_ptr。   简单实现: 1 template<class T> 2 class AutoPointer 3 { 4 public: 5 AutoPointer(T* ptr) 6 :mPointer(ptr){} 7 8 AutoPointer(AutoPointer<T>& other) 9 { 10 mPointer= other.mPointer; //管理权进⾏转移 11 other.mPointer= NULL; 12 } 13 14 AutoPointer& operator = (AutoPointer<T>& other) 15 { 16 if(this != &other) 17 { 18 delete mPointer; 19 mPointer = other.mPointer; //管理权进⾏转移 20 other.mPointer= NULL; 21 } 22 23 return *this; 24 } 25 26 ~AutoPointer() 27 { 28 delete mP

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值