动态内存与智能指针及其实现

  • Post author:
  • Post category:其他


详解请参照

智能指针详解


本文主要依据C++ primer的基础知识分析智能指针,并最后给出智能指针的实现;


shared_ptr

  • shared_ptr允许多个指针指向同一个对象
  • shared_ptr是实现为模板,当创建一个智能指针时,必须提供额外的信息—-指针可以指向的类型;
  • 最安全的分配和使用动态内存的方法是调用一个名为make_shared的标准库函数,此函数在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr;


    • shared_pre<int> p = make_shared<int>(42);
    • shared_ptr的析构函数会递减它所指向的对象的引用计数,如果引用计数变为0,shared_ptr的析构函数就会销毁对象,并释放它所占用的内存;
    • shared_ptr在无用之后仍然保留的一种可能是,将shared_ptr存放在一个容器中,随后重排了容器,从而不再需要某些元素,在此情况下,应该确保用erase删除那些不再需要的shared_ptr元素;

直接管理内存

  • 默认情况下,动态分配的对象是默认初始化的,这意味着内置类型或组合类型的对象将是未定义的,而类类型对象将用默认构造函数进行初始化;

    • 值初始化的内置类型对象有着良好定义的值,而默认初始化的对象的值则是未定义的;
    • 用new分配const 对象是合法的,一个动态分配的const 对象必须进行初始化,想要释放一个const 动态对象,只要delete 指向它的指针即可;
    • 由内置指针(而不是智能指针)管理的内存在被显式释放前一直都会存在;
  • 使用new和delete管理动态内存存在三个常见问题:

    • 忘记delete内存;
    • 使用已释放掉的对象;
    • 同一块内存释放两次;
  • 动态内存的一个基本问题是可能有多个指针指向相同的内存,在delete 内存之后重置指针的方法只对这个指针有效,对其他任何仍指向(已释放的)内存的指针是无作用的;

shared_ptr和new结合使用

  • 可以用new返回的指针初始化智能指针,

    必须使用直接初始化的形式初始化一个智能指针:


    • shared_ptr<int> p(new int(1024));
    • 一个用来初始化智能指针的普通指针必须指向动态内存;

    • 当将一个shared_ptr 绑定到一个普通指针时,就将内存的管理责任交给了这个shared_ptr,一旦这样做了,就不应该再使用内置指针来访问来访问这个shared_ptr 所指向的内存;

      • 使用内置指针访问一个智能指针所负责的对象是很危险的,因为我们无法知道对象何时被销毁;
    • get用来将指针的访问权限传递给代码,

      只有在确定代码不会delete指针的情况下才能使用get。特别是,永远不要用get初始化另一个智能指针或为另一个智能指针赋值;
  • 智能指针可以提供对动态分配的内存安全又方便的管理,但这建立在正确使用的前提下,为了正确使用智能指针,必须坚持一些基本规范:

    • 不使用相同的内置指针值初始化(或reset)多个智能指针;
    • 不delete get()返回的指针;
    • 不使用get() 初始化或reset 另一个智能指针;
    • 如果使用get() 返回的指针,记住当最后一个对应的智能指针销毁后,你的指针就变为无效了;
    • 如果你使用智能指针管理的资源不是new 分配的内存,记住传递给它一个删除器;


智能指针的简单实现:

#include<iostream>

using namespace std;

template<typename T>
class SmartPointer{
private:
    T* ptr;
    size_t* reference_count;
    void releaseCount(){
        if (ptr){
            (*reference_count)--;
            if ((*reference_count) == 0){
                delete ptr;
                delete reference_count;
            }
        }
    }
public:
    SmartPointer(T* p = 0) :ptr(p), reference_count(new size_t){
        if (p)*reference_count = 1;
        else *reference_count = 0;
    }
    SmartPointer(const SmartPointer& src){
        if (this != &src){
            ptr = src.ptr;
            reference_count = src.reference_count;
            (*reference_count)++;
        }
    }
    SmartPointer& operator=(const SmartPointer& src){
        if (ptr == src.ptr)return *this;
        releaseCount();
        ptr = src.ptr;
        reference_count = src.reference_count;
        (*reference_count)++;
        return *this;
    }
    T* operator*(){
        return (*ptr);
    }
    T* operator->(){
        return ptr;
    }
    ~SmartPointer(){
        if (--(*reference_count) == 0){
            delete ptr;
            delete reference_count;
        }
    }
    size_t get_reference(){
        return *reference_count;
    }
};

int main(){
    SmartPointer<char> cp1(new char('a'));
    cout << "cp1.reference_count = " << (cp1.get_reference()) << endl;
    SmartPointer<char> cp2(cp1);
    cout << "cp1.reference_count = " << (cp1.get_reference()) << endl;
    cout << "cp2.reference_count = " << (cp2.get_reference()) << endl;
    SmartPointer<char> cp3 = cp2;
    cout << "cp2.reference_count = " << (cp2.get_reference()) << endl;
    cp3 = cp1;
    cout << "cp3.reference_count = " << (cp3.get_reference()) << endl;
    cp3 = cp3;
    SmartPointer<char> cp4(new char('b'));
    cp3 = cp4;
    cout << "cp4.reference_count = " << (cp4.get_reference()) << endl;
    cout << "cp3.reference_count = " << (cp3.get_reference()) << endl;
    cout << "cp2.reference_count = " << (cp2.get_reference()) << endl;
    system("pause");
    return 0;
}


unique_ptr

  • 某个时刻只能有一个unique_ptr 指向一个给定对象,定义一个unique_ptr时,需要将其绑定到一个new 返回的指针上,初始化unique_ptr必须采用直接初始化形式;

    • unique_ptr 不支持普通的拷贝或赋值操作;
    • 可以通过release 或 reset将指针的所有权从一个(非const)unique_ptr转移给另一个unique_ptr;
    • unique_ptr 默认情况下用delete 释放它所指向的对象,也可以提供一个指定类型的删除器;



版权声明:本文为u010150046原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。