关于智能指针的一个疑问

     c++中最大的问题就是内存管理问题也就是指针,当一个指针在程序中到处传的时候,经常会出现多次销毁,或者用到一个已经被释放的指针(野指针),特别是在多线程中这种情况更加难以处理,根本不知道什么时候会在哪个线程中被释放,虽然c++11中的智能指针有效的解决了这个问题,在很大程度上简化了内存管理的难度,但是使用不当还是会导致程序崩溃,比如你在使用的时候把一个智能指针reset或者把nullptr赋给了目标智能指针,这个时候裸指针起最根本的问题还是会暴露出来,究其根本还是智能指针的设计导致的。

      _Tp*
      operator->() const noexcept
      {
	_GLIBCXX_DEBUG_PEDASSERT(_M_ptr != 0);
	return _M_ptr;
      }

     当我们使用智能指针的时候其实是调用了智能指针魔板累的->操作符重载函数,我们可以看到这个函数noexcept标记,标准委员默认调用此函数时_M_ptr一定不为空,再一次大权还给了程序员,人都是会犯错的,而这些错都不是我们想犯得,虽然我们总是提醒自己使用前做不为空判断,但是有时候就是会忘,更重要的是在多线程环境中如果你没有保证判断和判断后的逻辑是线程安全的,这个判断是不可信的,最终还是会崩溃。

    我一直在考虑c++能不能像java等一些语言使用对象指针,在对象为空时抛出异常而不是崩溃,但是这个逻辑不能靠程序员在每次使用时做判断来实现,这个判断只能是预防,而最终需要一个屏障来百分之百拦截所有的异常。想了很久都没有找到好的办法,直到我看到了这个函数,突然想到了解决的办法,就是重写智能指针的->重载操作函数,只要重写这一个函数所有的问题都解决了。下面是我的一个小小的例子。

//  Created by 杜国超 on 19/6/22.
//  Copyright © 2019年 杜国超. All rights reserved.
//


#ifndef DEMO_SA_SHAPTR_H
#define DEMO_SA_SHAPTR_H

#include <memory>
#include <execinfo.h>

template<typename _Tp>
class sa_shaptr : public std::shared_ptr<_Tp> {
public:


    constexpr sa_shaptr() noexcept
            : std::shared_ptr<_Tp>() {}

    sa_shaptr(const sa_shaptr<_Tp> &) noexcept = default;

    sa_shaptr(std::shared_ptr<_Tp> ptr)
            : std::shared_ptr<_Tp>(ptr) {}

    template<typename _Tp1>
    explicit sa_shaptr(_Tp1 *__p)
            : std::shared_ptr<_Tp>(__p) {}


    _Tp *
    operator->() const {
        _Tp *pTp = this->get();
        if (pTp == nullptr) {
            printStack();
            throw std::runtime_error("The sa_shaptr get a null ptr");
        }
        return pTp;
    }


    void printStack(void) const {
        int j, nptrs;
        void *stack[100];
        char **strings;
        nptrs = backtrace(stack, 100);
        strings = backtrace_symbols(stack, nptrs);
        if (strings == nullptr) {
            perror("backtrace_symbols");
            exit(EXIT_FAILURE);

        }

        for (j = 0; j < nptrs; j++) {
            printf("%s\n", strings[j]);
        }

        free(strings);
    }


};

#endif //DEMO_SA_SHAPTR_H

//  Created by 杜国超 on 19/6/22.
//  Copyright © 2019年 杜国超. All rights reserved.
//

#include <memory>
#include <iostream>
#include "sa_shaptr.h"

class People {
public:
    People(const std::string &name) : name(name) {}

    void SayName() {
        printf("My name is %s\n", name.data());
    }

private:
    std::string name;
};

int main() {
//    std::shared_ptr<People> sharedPtr;
//    sharedPtr->SayName();
    sa_shaptr<People> shaptr = std::make_shared<People>("Oliver Queen");
    shaptr->SayName();
    shaptr.reset();
    try {
        shaptr->SayName();
    } catch (std::exception &e) {
        printf("Catch a exception %s\n", e.what());
    }

    std::cout << "Hello, Dears!" << std::endl;
    return 0;
}

   

      一个好的系统所有的逻辑处理都会有一个统一的入口我们暂且称之为消息路由器,我们只需要在这里捕获所有的异常然后在次处理程序错误即可,这样一个消息逻辑异常并不会导致整个系统的崩溃,其他消息可正常运行,这样我们就可以像java对象一样使用智能指针。当然这里仅仅是一个解决问题的思路和一个小小的例子,如果要实用到项目中像shared_ptr一样使用,需要把shared_ptr里所有的操作符重载函数都要实现一遍才行。

 

    

    

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值