• C++个人使用经验手册


    引言

    持续更新中…
    个人经验记录笔记而已,仅供参考,下附各种官方学习网站:
    boost库中文网:http://zh.highscore.de/cpp/boost/smartpointers.html
    cpp reference中文网:https://zh.cppreference.com/w/%E9%A6%96%E9%A1%B5

    boost::scoped_ptr使用小结

    一个作用域指针独占一个动态分配的对象。 对应的类名为 boost::scoped_ptr,它的定义在 boost/scoped_ptr.hpp 中。 不像 std::auto_ptr,一个作用域指针不能传递它所包含的对象的所有权到另一个作用域指针。 一旦用一个地址来初始化,这个动态分配的对象将在析构阶段释放。
    因为一个作用域指针只是简单保存和独占一个内存地址,所以 boost::scoped_ptr 的实现就要比 std::auto_ptr 简单。 在不需要所有权传递的时候应该优先使用 boost::scoped_ptr 。 在这些情况下,比起 std::auto_ptr 它是一个更好的选择,因为可以避免不经意间的所有权传递。

    #include  
    
    int main() 
    { 
      boost::scoped_ptr<int> i(new int); 
      *i = 1; 
      *i.get() = 2; 
      i.reset(new int); 
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    使用reset时会为其初始化新指向的对象,原指向的对象会被释放。
    我们不能对scoped_ptr进行任何赋值操作,无论是在=左侧还是右侧
    通常,如果我们在一个类中用scoped_ptr定义了一个指针,那意味着每个新的对象都需要独立初始化一个该指针,如下:

    class BClass {
    public:
        BClass();
        virtual ~BClass();
        bool is_bclass();
    private:
        int m_b;
    };
    class AClass {
    public:
        AClass();
        AClass(int, BClass*);
        virtual ~AClass();
    private:
        int m_a;
        boost::scoped_ptr<BClass> m_bclassor;
    };
    // 我们不能定义下面这种构造函数,即时定义了也用不了,因为不能将b_class的值赋值给一个scope_ptr变量
    AClass::AClass(int a, BClass* b_class) : m_a(a), m_bclass(b_class) {};
    // 只能在构造函数里初始化该指针
    AClass::AClass() : m_bclass(new BClass()) {}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    如果我们是希望能在A中存储另外一个已经初始化好的其他类指针,最好不要用。

    使用的时候一般都是m_bclassor.get()->is_bclass()这种方式

    禁用类的某个功能,可将该功能定义为私有成员 – scoped_ptr源码启示

    像scoped_ptr就是将=运算符、比较运算符==、!=进行了重载,禁止了拷贝构造

    template<class T> class scoped_ptr // noncopyable                                                                                                                                                                   
    {
    private:
    
        T * px;
      //拷贝构造函数,复制函数私有化,防止复制
        scoped_ptr(scoped_ptr const &);
        scoped_ptr & operator=(scoped_ptr const &);
    
        typedef scoped_ptr<T> this_type;
        //禁止同类对象进行一致性比较
        void operator==( scoped_ptr const& ) const;
        void operator!=( scoped_ptr const& ) const;
    
    public:
    
        typedef T element_type;
        //显式构造函数
        explicit scoped_ptr( T * p = 0 ): px( p ) // never throws
        {
    #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
            boost::sp_scalar_constructor_hook( px );
    #endif
        }
    
    #ifndef BOOST_NO_AUTO_PTR
    
        explicit scoped_ptr( std::auto_ptr<T> p ) BOOST_NOEXCEPT : px( p.release() )
        {
    #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
            boost::sp_scalar_constructor_hook( px );
    #endif
        }
    
    #endif
        //析构函数
        ~scoped_ptr() // never throws
        {
    #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
            boost::sp_scalar_destructor_hook( px );
    #endif
            boost::checked_delete( px );
        }
        //重置指针,
        void reset(T * p = 0) // never throws
        {
            BOOST_ASSERT( p == 0 || p != px ); // catch self-reset errors
            this_type(p).swap(*this);
        }
        //*操作符重载
        T & operator*() const // never throws
        {
            BOOST_ASSERT( px != 0 );
            return *px;
        }
        //->操作符重载
        T * operator->() const // never throws                                                                                                                                                                          
        {
            BOOST_ASSERT( px != 0 );
            return px;
        }
        //get返回对象指针,返回的指针不能作delete操作,不然会发生未定义行为
        T * get() const BOOST_NOEXCEPT
        {
            return px;
        }
    
    // implicit conversion to "bool"
    #include 
        //用于交换两个scoped_ptr保存的指针
        void swap(scoped_ptr & b) BOOST_NOEXCEPT
        {
            T * tmp = b.px;
            b.px = px;
            px = tmp;
        }
    };
    
    #if !defined( BOOST_NO_CXX11_NULLPTR )
    //与空指针进行比较
    template<class T> inline bool operator==( scoped_ptr<T> const & p, boost::detail::sp_nullptr_t ) BOOST_NOEXCEPT
    {
        return p.get() == 0;
    }
    
    template<class T> inline bool operator==( boost::detail::sp_nullptr_t, scoped_ptr<T> const & p ) BOOST_NOEXCEPT
    {
        return p.get() == 0;
    }
    
    template<class T> inline bool operator!=( scoped_ptr<T> const & p, boost::detail::sp_nullptr_t ) BOOST_NOEXCEPT
    {
        return p.get() != 0;
    }
    
    template<class T> inline bool operator!=( boost::detail::sp_nullptr_t, scoped_ptr<T> const & p ) BOOST_NOEXCEPT
    {
        return p.get() != 0;
    }
    
    #endif
    //交换函数
    template<class T> inline void swap(scoped_ptr<T> & a, scoped_ptr<T> & b) BOOST_NOEXCEPT
    {
        a.swap(b);
    }
    //get_pointer方法,类似get()方法。
    template<class T> inline T * get_pointer(scoped_ptr<T> const & p) BOOST_NOEXCEPT
    {
        return p.get();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112

    std::vector的reserve函数的坑

    使用reserve()函数,可以使vector预留指定数量的空间,使得添加元素时不会触发重新分配内存的操作,从而提高程序的效率。但同时需要注意reserve函数不会初始化数组,如果直接使用会出core。

    std::uniq_ptr

    std::unique_ptr 是通过指针占有并管理另一对象,并在 unique_ptr 离开作用域时释放该对象的智能指针。
    在下列两者之一发生时用关联的删除器释放对象:

    • 销毁了管理的 unique_ptr 对象
    • 通过 operator= 或 reset() 赋值另一指针给管理的 unique_ptr 对象。

    实践重点:
    与上面的scoped_ptr不同的是,它可以通过:

    A* ptr1 = uniq_ptr;
    
    • 1

    这种方式,将原uniq_ptr的管理权交给ptr1,但与次同时,原uniq_ptr不在拥有对原对象的管理所有权,如果再次使用uniq_ptr操作对象会出现运行时错误,对大型服务来说是很致命的,这是需要特别注意的。至于通过新构造一个对象reset进去,与scoped_ptr类似。
    其他三个关注点:
    (1)unique_ptr 亦可以不占有对象,该情况下称它为空 (empty);
    (2)可移动构造或移动赋值,不可拷贝构造或拷贝赋值;
    (3)只有非 const 的 unique_ptr 能转移被管理对象的所有权给另一 unique_ptr 。若对象的生存期为 const std::unique_ptr 所管理,则它被限定在创建指针的作用域中。

    guard方式加锁

    所谓guard方式加锁,就是让锁出作用于后自动销毁,这种写法有能避免遗漏解锁而导致的死锁,有人可能会想我怎么可能会忘解锁,这种场景很常见,比如:

    std::map<std::string, T data> G_data_map;
    bool get_my_data(const std::string& key, 
                     T& my_data) {
        pthread_rwlock_rdlock(&_intervent_info_rwlock);
        auto it = G_data_map.find(key);
        if (it == G_data_map.end()) {
            return false;
        }
        my_data = it->second;
        pthread_rwlock_unlock(&_intervent_info_rwlock);
        
        return true;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    上面这段代码在返回的时候就没有解锁就返回了。这种是在开发中很容易犯的问题。特别是加锁的代码范围比较大的时候。
    如果使用linux系统库的锁api,可以自己封装一个锁的类,在析构函数里面释放锁即可,这样就实现了简单实用的guard方式。

  • 相关阅读:
    Redis常用数据结构操作与底层原理
    1.1 网页的基本概念
    2022年《数据结构试验》上机考试一(计科2103,2105班+数据2101,2102班)题解
    确定了,2022下半年软考报名8月开始
    【RapidAI】P1 中文文本切割程序
    java插值查找(含插值查找的代码)
    YB6502是一款5V输入支持两节串联磷酸铁锂电池的升压充电管理应用
    【文章学习系列之模型】Koopa
    IOS 关于CoreText的笔记
    【大数据】flink 读取文件数据写入ElasticSearch
  • 原文地址:https://blog.csdn.net/qq_42936727/article/details/134441722