智能指针C++11

(读书笔记:全部摘抄自cPP标注库)

C++ 11 中,标准库提供了两大类smart pointer:

1. Class shared_ptr 实现共享式拥有(shared ownership)概念。多个 只能指针 可以指向相同的对象,改对象和其相关资源会在 “最后一个reference被销毁” 时释放。为了在结构较为复杂的情境中执行上述工作,标准库提供了weak_ptr ,bad_weak_ptr  和 enable_shared_from_this等辅助类。

2,Class_unique_ptr 实现独占式拥有(exclusive ownership) 或 严格拥有(strict ownership)概念。保证同一时间内只有一个smart pointer可以指向该对象。你可以移交拥有权。他对于 避免资源泄露特别有用。

c++98只让c++标准库提供一个smart pointer class : auto_ptr<>,其设计是为了执行现今的unique_ptr所提供的服务。然而由于当时缺乏语言特性如“针对构造和赋值”的move语义,以及其他瑕疵,这个class不易被理解且容易出错。因此在TR1引入clss shared_ptr,c++11引入class unique_ptr之后,auto_ptr成为c++11中被证实反对的成分,除非老旧代码需要编译,否则你不应使用它。

所有smart pointer class 都被定义于头文件<memory>内。

shard_ptr 的目标是没有蛀牙(在其所指向的对象不再被需要之后,自动释放与对象相关的资源)。

使用shard_ptr 

#include<iostream>
#include<string>
#include<vector>
#include<memory>

using namespace std;

int main(){
    shared_ptr<string> pNico(new string("nico"));
    shared_ptr<string> pJutta(new string("jutta"));

    (*pNico)[0] = 'N';
    pJutta->replace(0,1,"J");

    vector<shared_ptr<string>> whoMadeCoffee;
    whoMadeCoffee.push_back(pJutta);
    whoMadeCoffee.push_back(pJutta);
    whoMadeCoffee.push_back(pNico);
    whoMadeCoffee.push_back(pNico);
    for(auto ptr : whoMadeCoffee) {
        cout << *ptr << "   ";
    }
    cout << endl;

    *pNico = " Nicolai";

    for(auto ptr : whoMadeCoffee) {
        cout << *ptr << "   ";
    }
    cout << endl;

    cout << "use_cout " << whoMadeCoffee[0].use_count() << endl;
}

需要注意的是,由于“接受单一pointer作为唯一实参" 的构造函数是explicit,所以这里不能使用赋值符,因为那样的话会被视为需要一个隐式转换,然而新式的语法是被接受的:

shared_ptr<string> pNico = new string("nico");  //ERROR
shared_ptr<string> pNico{new string("nico")};   //OK

也可以使用便捷的 make_shared() :

shared_ptr<string> pNico = make_shared<string>("nico");

这种方式比较快,也比较安全,因为它使用一次而非二次分配:一次针对对象,另一次针对"shared pointer 用以控制对象" 的shared data。

另一种写法是,先声明shard pointer ,然后对它赋值一个new pointer,然后不可以使用assignment操作符,必须改用reset():

pNico3 = new string("nico");    //ERROR :no assignment for ordinary pointers
pNico3.reset(new string("nico"));   //Ok

定义一个Deleter

定义一个deleter,例如让它在“删除被指向对象”之前先打印一条信息:

shared_ptr<string> pNico(new string("nico"),
                         [](string * p){
                             cout << "delete " << *p << endl;
                             delete p;
                         });
pNico = nullptr;  //pNico does not refer to string any longer
whoMadeCoffee.resize(2);   // all copies of string in pNico are destoryed                   

其中函数对象 D del参数是一个lambda表达式。

关于shared_ptr 的构造函数,参考链接

对付Array

shared_ptr提供的default deleter 调用的是delete,不是delete[] ,这意味着局限性,只有当shared_ptr拥有“由new建立起来的单一对象”,default deleter才试用。然而很不幸,为array建立一个shared_ptr是可能的,却是错误的:

std::shared_ptr<int> p(new int[10]); //ERROR,but compiles

故,如果你试用new[]建立一个array of object ,必须自己定义自己deleter。你可以传递一个函数,或者函数对象,或者lambda,让它们针对传入的寻常指针调用delete[]。例如:

shared_ptr<int> p(new int[10],
                        [](int *p) {
                            delete[] p;
                        });

也可以试用为unique_ptr而提供的辅助函数作为deleter,其内调用deleter[]:

std::shared_ptr<int> p(new int[10], std::default_delete<int[]> ());

需要注意的是:shared_ptr 和unique_ptr 以稍稍不同的方式处理deleter。例如unique_ptr允许只传递对应的元素类型作为template实参,但这对shared_ptr就不行:

std::unique_ptr<int[]> p(new int[10]);  //OK
std::shared_ptr<int[]> p(new int[10]);  //ERROR:does not compile

此外,对于 unique_ptr,你必须明确给予第二个template实参,指出自己的deleter:

std::unique_ptr<int,void(*)(int *)> p(new int[10], [](int *p) {
                            delete[] p;
});                       

还需注意,shared_ptr不提供operator[]。至于unique_ptr,它有一个针对array的偏特化版本,该版本提供operator[] 取代 operator* 和 operator-> 。之所以有此差异是因为,unique_ptr在效能和弹性上进行了优化。

猜你喜欢

转载自www.cnblogs.com/gardenofhu/p/9283415.html