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

来源:互联网 发布:朗读软件手机版 编辑:程序博客网 时间:2024/05/16 09:07

详解请参照智能指针详解

本文主要依据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 释放它所指向的对象,也可以提供一个指定类型的删除器;