这篇文章记述了关于C++11 智能指针的知识点。
动态内存 到目前为止,我们编写的程序中所使用的对象都有着严格定义的生存期。全局对象在程序启动时分配,在程序结束时销毁。对于局部自动对象,当我们进入其定义所在的程序块时被创建,在离开块时被销毁。局部static对象在第一次使用前分配,在程序结束时销毁。
除了自动和static对象外,C++还支持动态分配对象。动态分配的对象的生存期与它们在哪里创建是无关的,只有当显式地被释放时,这些对象才会销毁。
动态对象的正确释放被证明是编程中极易出错的地方。为了更安全的使用动态对象,标准库定义了两个智能指针类型来管理动态分配的对象。当一个对象应该被释放时,指向它的智能指针可以确保自动地释放它。
我们的程序到目前为止只使用过静态内存或栈内存。静态内存用来保存局部static对象:static int counter 函数调用次数。类static数据成员以及定义在任何函数之外的变量。栈内存用来保存定义在函数内的非static对象。分配在静态或栈内存中的对象由编译器自动创建和销毁。对于栈对象,仅在其定义的程序块运行时才存在:static对象在使用之前分配,在程序结束时销毁。
除了静态内存和栈内存,每个程序还拥有一个内存池。这部分内存被称为自由空间或堆。程序用堆来存储动态分配的对象—即那些在程序运行时分配的对象。动态对象的生存期由程序来控制,也就是说,当动态对象不再使用时,我们的代码必须显式地销毁它们。
类static数据成员
有的时候类需要它的一些成员与类本身直接相关,而不是和类的各个对象保持关联。
例如,一个银行账户类需要一个数据成员来表示当前的基准利率。在此例中,我们希望利率与类关联,而非与类的每个对象关联。从实现效率的角度来看,没必要为每个对象都储存利率信息。而且更加中重要的是,一旦利率浮动,我们希望所有的对象都能使用新的值。
1 2 3 4 5 6 7 8 9 10 11 class Account { public calculate () {amount += amount * interestRate;} static double rate () {return interestRate;} static void rate (double ) ; private : std::string owner; double amount; static double interestRate; static double initRate () ; }
类的静态成员存在于任何对象之外,对象中不包含任何与静态数据成员有关的数据。因此,每个Account对象将包含两个数据成员:owner和amount。只存在一个interestRate对象而且它被所有Account对象共享。
动态内存与智能指针 C++中,动态内存的管理是通过一对运算符来完成的:new,在动态内存中为对象分配空间并返回一个指向该对象的指针,我们可以选择对对象进行初始化;delete,接受一个动态对象指针,销毁该对象,并释放与之相关联的内存。
为了更容易同时更安全地使用动态内存,新的标准库提供了两种智能指针类型来管理动态对象。智能指针的行为类似常规指针,重要的区别是它负责自动释放所指向的对象。这两种智能指针的区别在于管理底层指针的方式:shared_ptr允许多个指针指向同一个对象;unique_ptr则独占所指向的对象。此外还有一个weak_ptr的伴随类,它是一种弱引用,指向shared_ptr所管理的对象。避免两个shared_ptr相互引用造成死锁的局面。
shared_ptr shared_ptr p1;
shared_ptr<list> p2;
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 #include "stdafx.h" #include <iostream> #include <future> #include <thread> using namespace std ;class Person { public : Person(int v) { value = v; std ::cout << "Cons" <<value<< std ::endl ; } ~Person() { std ::cout << "Des" <<value<< std ::endl ; } int value; }; int main () { std ::shared_ptr <Person> p1 (new Person(1 )) ; std ::shared_ptr <Person> p2 = std ::make_shared<Person>(2 ); p1.reset(new Person(3 )); std ::shared_ptr <Person> p3 = p1; p1.reset(); p3.reset(); return 0 ; }
reset()包含两个操作。当智能指针中有值的时候,调用reset()会使引用计数减1.当调用reset(new xxx())重新赋值时,智能指针首先是生成新对象,然后将就对象的引用计数减1(当然,如果发现引用计数为0时,则析构旧对象),然后将新对象的指针交给智能指针保管。
手写智能指针 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 113 114 #pragma once template <class T >class SharedPointer { public : SharedPointer() :m_refCount(nullptr ), m_pointer(nullptr ) {} SharedPointer(T* adoptTarget) :m_refCount(nullptr ), m_pointer(adoptTarget) { addReference(); } SharedPointer(const SharedPointer<T>& copy) :m_refCount(copy.m_refCount), m_pointer(copy.m_pointer) { addReference(); } virtual ~SharedPointer() { removeReference(); } SharedPointer<T>& operator =(const SharedPointer<T>& that) { if (this != &that) { removeReference(); this ->m_pointer = that.m_pointer; this ->m_refCount = that.m_refCount; addReference(); } return *this ; } bool operator ==(const SharedPointer<T>& other) { return m_pointer == other.m_pointer; } bool operator !=(const SharedPointer<T>& other) { return !operator ==(other); } T& operator *() const { return *m_pointer; } T* operator ->() const { return m_pointer; } int GetReferenceCount () const { if (m_refCount) { return *m_refCount; } else { return -1 ; } } protected : void addReference () { if (m_refCount) { (*m_refCount)++; } else { m_refCount = new int (0 ); *m_refCount = 1 ; } } void removeReference () { if (m_refCount) { (*m_refCount)--; if (*m_refCount == 0 ) { delete m_refCount; delete m_pointer; m_refCount = 0 ; m_pointer = 0 ; } } } private : int * m_refCount; T* m_pointer; };