C++ 11 创建和使用 shared_ptr

shared_ptr 的类型是C + +标准库中一个聪明的指针,是为多个拥有者管理内存中对象的生命周期而设计的。在你初始化一个 shared_ptr 后,你可以复制它,把函数参数的值递给它,并把它分配给其它 shared_ptr 实例。所有实例指向同一个对象,并共享访问一个“控制块”,即每当一个新的shared_ptr 被添加时,递增和递减引用计数,超出范围,则复位。当引用计数到达零时,控制块删除内存资源和自身。

下图显示了指向一个内存位置的几个 shared_ptr 实例。

无论什么时候,当内存资源被第一次被创建时,就使用函数 make_shared (<memory>) 创建一个新的 shared_ptr。 make_shared异常安全。它使用同一调用分配的内存控制块和资源从而减少构造开销。如果你不使用 make_shared,那么在把它传递给 shared_ptr 的构造函数之前,你必须使用一个明确的新表达式创建的对象。下面的例子显示了在新对象中声明和初始化一个 shared_ptr 的各种方式。

class Song
{
public:
    Song(std::string str1, std::string str2);
    ~Song();
private:
    std::string name;
    std::string action;
};
// Use make_shared function when possible.
auto sp1 = make_shared<Song>(L"The Beatles", L"Im Happy Just to Dance With You");

// Ok, but slightly less efficient.
// Note: Using new expression as constructor argument
// creates no named variable for other code to access.
shared_ptr<Song> sp2(new Song(L"Lady Gaga", L"Just Dance"));

// When initialization must be separate from declaration, e.g. class members,
// initialize with nullptr to make your programming intent explicit.
shared_ptr<Song> sp5(nullptr);
//Equivalent to: shared_ptr<Song> sp5;
//...
sp5 = make_shared<Song>(L"Elton John", L"I‘m Still Standing");

下面的示例演示如何声明和初始化一个已经被分配了另一个 shared_ptr 的对象共享所有权的 shared_ptr 的实例。假设 sp2 是一个初始化的shared_ptr

//Initialize with copy constructor. Increments ref count.
auto sp3(sp2);

//Initialize via assignment. Increments ref count.
auto sp4 = sp2;

//Initialize with nullptr. sp7 is empty.
shared_ptr<Song> sp7(nullptr);      //此指针有指向类型,但是指向nullptr

// Initialize with another shared_ptr. sp1 and sp2
// swap pointers as well as ref counts.
sp1.swap(sp2);

当您使用算法复制元素时,shared_ptr 的也是很有用的标准模板库(STL)。你可以把元素包装在 shared_ptr 里,然后将其复制到其他容器,只要你需要它,底层的内存始终是有效的。以下示例演示如何使用 replace_copy_if 算法来创建一个 shared_ptr 的实例以及如何在一个向量上进行使用。

vector<shared_ptr<Song>> v;

v.push_back(make_shared<Song>(L"Bob Dylan", L"The Times They Are A Changing"));
v.push_back(make_shared<Song>(L"Aretha Franklin", L"Bridge Over Troubled Water"));
v.push_back(make_shared<Song>(L"Thalxa", L"Entre El Mar y Una Estrella"));

vector<shared_ptr<Song>> v2;
remove_copy_if(v.begin(), v.end(), back_inserter(v2), [] (shared_ptr<Song> s)
{
    return s->artist.compare(L"Bob Dylan") == 0;
});

for (const auto& s : v2)
{
    wcout << s->artist << L":" << s->title << endl;
}

你可以用 dynamic_pointer_cast, static_pointer_cast 和 const_pointer_cast 来转换shared_ptr。这些函数的操作类似 dynamic_caststatic_cast 和 const_cast。下面的示例演示如何测试在基类的 shared_ptr 向量中的每个元素的派生类,,然后复制元素,并显示它们的信息。

vector<shared_ptr<MediaAsset>> assets;

assets.push_back(shared_ptr<Song>(new Song(L"Himesh Reshammiya", L"Tera Surroor")));
assets.push_back(shared_ptr<Song>(new Song(L"Penaz Masani", L"Tu Dil De De")));
assets.push_back(shared_ptr<Photo>(new Photo(L"2011-04-06", L"Redmond, WA", L"Soccer field at Microsoft.")));

vector<shared_ptr<MediaAsset>> photos;

copy_if(assets.begin(), assets.end(), back_inserter(photos), [] (shared_ptr<MediaAsset> p) -> bool
{
    // Use dynamic_pointer_cast to test whether
    // element is a shared_ptr<Photo>.
    shared_ptr<Photo> temp = dynamic_pointer_cast<Photo>(p);
    return temp.get() != nullptr;
});

for (const auto&  p : photos)
{
    // We know that the photos vector contains only
    // shared_ptr<Photo> objects, so use static_cast.
    wcout << "Photo location: " << (static_pointer_cast<Photo>(p))->location_ << endl;
}

你可以用下列方法把 shared_ptr 传递给另一个函数:

  • 向 shared_ptr 传递值。调用复制构造函数,递增引用计数,并把被调用方当做所有者。还有就是在这次操作中有少量的开销,这很大程度上取决于你传递了多少 shared_ptr 对象。当调用方和被调用方之间的代码协定 (隐式或显式) 要求被调用方是所有者,使用此选项。
  • 通过引用或常量引用来传递 shared_ptr。在这种情况下,引用计数不增加,并且只要调用方不超出范围,被调用方就可以访问指针。或者,被调用方可以决定创建一个基于引用的 shared_ptr,从而成为一个共享所有者。当调用者并不知道被被调用方,或当您必须传递一个 shared_ptr,并希望避免由于性能原因的复制操作,请使用此选项。
  • 通过底层的指针或引用底层的对象。这使得被调用方使用对象,但不使共享所有权或扩展生存期。如果被调用方从原始指针创建一个shared_ptr,则新的 shared_ptr 是独立于原来的,且没有控制底层的资源。当调用方和被调用方之间的协定中明确规定调用者保留shared_ptr 生存期的所有权,则使用此选项。
  • 当您决定如何传递一个 shared_ptr时,确定被调用方是否有共享基础资源的所有权。一个“所有者”就是只要它需要就可以使用底层资源的对象或函数。如果调用方必须保证被调用方可以在其(函数)生存期以外扩展指针的生存期,请使用第一个选项。如果您不关心被调用方是否扩展生存期,则通过引用传递并让被调用方复制它。
  • 如果不得不允许帮助程序函数访问底层指针,并且您知道帮助程序函数将使用指针且在调用函数返回前先返回,则该函数不必共享底层指针的所有权。仅仅是在调用方的 shared_ptr 的生存期内允许访问指针。在这种情况下,通过引用来传递 shared_ptr,通过原始指针或引用的基本对象都是安全的。通过此方式提供一个小的性能改进,并且还有助于表示程序的意图。
  • 有时,例如在一个 std:vector<shared_ptr<T>>中,您可能必须对传递每个 shared_ptr 给lambda表达式体或命名函数对象。如果lambda或函数没有存储指针,则通过引用传递 shared_ptr,以避免调用拷贝构造函数的每个元素。

下面的示例显示 shared_ptr 如何重载多种比较操作符,以使由 shared_ptr 实例所拥有的内存指针的比较。

// Initialize two separate raw pointers.
// Note that they contain the same values.
auto song1 = new Song(L"Village People", L"YMCA");
auto song2 = new Song(L"Village People", L"YMCA");

// Create two unrelated shared_ptrs.
shared_ptr<Song> p1(song1);
shared_ptr<Song> p2(song2);

// Unrelated shared_ptrs are never equal.
wcout << "p1 < p2 = " << std::boolalpha << (p1 < p2) << endl;
wcout << "p1 == p2 = " << std::boolalpha <<(p1 == p2) << endl;

// Related shared_ptr instances are always equal.
shared_ptr<Song> p3(p2);
wcout << "p3 == p2 = " << std::boolalpha << (p3 == p2) << endl; 

举例:

{
        //创建的空指针,有指针类型,但是没有指向对象
        std::shared_ptr<int> fPtr1;

        std::shared_ptr<int> fPtr2 = std::make_shared<int>(4);
        std::cout << "fPtr2 use_count:" << fPtr2.use_count() << std::endl;
        std::shared_ptr<int> fPtr3(fPtr2);
        std::cout << "fPtr2 use_count:" << fPtr2.use_count() << " fPtr3 use_count:" << fPtr3.use_count() << std::endl;
        std::shared_ptr<int> fPtr4 = std::make_shared<int>(10);
        //shared_ptr指针对象赋值可直接用=
        std::shared_ptr<int> fPtr5 = fPtr2;
        std::cout << "fPtr2 use_count:" << fPtr2.use_count() << " fPtr3 use_count:" << fPtr3.use_count() << std::endl;

        std::cout << "-------------------------------------------" << std::endl;
        //get() 返回指向对象的指针
        std::cout << "fPtr2 address:" << fPtr2.get() << " = fPtr3 address:" << fPtr3.get() << std::endl;
        //use_count 返回指针指向的对象的引用计数
        std::cout << "fPtr2 use_count:" << fPtr2.use_count() << " fPtr3 use_count:" << fPtr3.use_count() << std::endl;

        if (!fPtr1)
        {
            std::cout << "fPtr is nullptr" << std::endl;
        }

        std::cout << "-------------------------------------------" << std::endl;
        //swap 将还两个shared_ptr所指向的对象
        std::cout << "swap before fPtr2 = " << *fPtr2 << " fPtr4 = " << *fPtr4 << std::endl;
        fPtr4.swap(fPtr2);
        std::cout << "swap after fPtr2 = " << *fPtr2 << " fPtr4 = " << *fPtr4 << std::endl;
        //交换之后,引用计数也跟着变
        std::cout << "fPtr2 use_count:" << fPtr2.use_count() << " fPtr4 use_count:" << fPtr4.use_count() << std::endl;

        //返回shared_ptr指针指向的对象引用是否为1
        std::cout << "unique:" << std::boolalpha << fPtr1.unique() << std::endl;

        //reset 将当前shared指针计数设置为0,并将该指针所引用的对象计数减1,刷新所有引用此对象的shared指针
        std::cout << "before reset fPtr2 use_count = " << fPtr2.use_count() << " fPtr3 = " << fPtr3.use_count() << std::endl;
        fPtr3.reset();
        std::cout << "after reset  fPtr2 use_count = " << fPtr2.use_count() << " fPtr3 = " << fPtr3.use_count() << std::endl;

        std::cout << "-------------------------------------------" << std::endl;
        std::vector<std::tr1::shared_ptr<int> > numbers;

        numbers.push_back(std::tr1::shared_ptr<int>(new int(1)));
        numbers.push_back(std::tr1::shared_ptr<int>(new int(2)));
        numbers.push_back(std::tr1::shared_ptr<int>(new int(3)));

        //如果声明std::tr1::shared_ptr<const 类型>,而当前需要修改对象的值,
        //可以声明std::tr1::shared_ptr<int> sp = std::tr1::const_pointer_cast<int>(csp);
    }
时间: 2024-10-13 22:25:57

C++ 11 创建和使用 shared_ptr的相关文章

C++ 11智能指针之shared_ptr

 shared_ptr是一个引用计数智能指针,用于共享对象的所有权.它可以从一个裸指针.另一个shared_ptr.一个auto_ptr.或者一个weak_ptr构造.还可以传递第二个参数给shared_ptr的构造函数,它被称为删除器(deleter).删除器用于处理共享资源的释放,这对于管理那些不是用new分配也不是用delete释放的资源时非常有用.shared_ptr被创建后,就可以像普通指针一样使用了,除了一点,它不能被显式地删除.shared_ptr的比较重要的接口如下: tem

C++ 11 创建和使用共享 weak_ptr

有时对象必须存储一种方法,用来在不引起引用计数增加的情况下访问 shared_ptr 的基础对象.通常,当您在 shared_ptr 实例之间循环引用时,就会出现此情况. 最佳的设计能够尽可能地避免指针具有共享所有权.但是,如果您必须具有共享的 shared_ptr 实例所有权,请避免在实例之间进行循环引用.如果循环引用不可避免,甚至由于某种原因而更为可取,请使用 weak_ptr 为一个或多个所有者提供对其他 shared_ptr 的弱引用.使用 weak_ptr,您可以创建连接到现有相关实例

使用Django1.11创建简单的资产管理平台

1:首先创建一个django项目 [[email protected] opt]# django-admin startproject opsCommandError: '/opt/ops' already exists[[email protected] opt]# cd ops[[email protected] ops]# tree.├── manage.py└── ops    ├── __init__.py    ├── settings.py    ├── urls.py    └─

Windows server2008/2012 安装oracle 11 创建实例HANG住在百分之2

Windows server2008/2012 安装oracle 11.2.0.1的时候,可能会在创建数据库实例的时候卡在百分之2的地方. 这个时候可以 1.点击开始菜单,在“搜索程序和文件”中输入“msconfig”,回车即打开“系统配置”对话框, 请在此对话框中切换到“引导”标签,然后单击图中红圈处的“高级选项”按钮,弹出引导高级选项对话框. 2.在弹出的“引导高级选项”对话框中勾选处理器数,建议修改为系统最大核数的一半. 3.修改完毕后,点击“确定”按钮,保存设置退出即可. 4.然后重新配

C++ 11 创建和使用 unique_ptr

unique_ptr 不共享它的指针.它无法复制到其他 unique_ptr,无法通过值传递到函数,也无法用于需要副本的任何标准模板库 (STL) 算法.只能移动unique_ptr.这意味着,内存资源所有权将转移到另一 unique_ptr,并且原始 unique_ptr 不再拥有此资源.我们建议你将对象限制为由一个所有者所有,因为多个所有权会使程序逻辑变得复杂.因此,当需要智能指针用于纯 C++ 对象时,可使用 unique_ptr,而当构造 unique_ptr 时,可使用make_uni

Powershell AWS 自动化管理 (11) - 创建一个高可用的WordPress博客(中)

理论和基本架构在上一篇已经做了说明,这一篇直接来看看具体的脚本实现吧.首先来看看前面10个步骤的实现. 创建EC2-S3的Role,这个Role是分配给EC2虚拟机的,这样他们创建之后自动就有权限访问S3的内容. 创建VPC网络 创建VPC的2个子网,位于不同的AZ 创建Internet网关 配置路由表 创建并配置EC2的Security Group,确保80和22端口可用 创建高可用的MariaDB数据库 配置数据库的Security Group,确保3306端口可用 创建S3 Bucket

Windows Azure Virtual Network (11) 创建VNet-to-VNet的连接

<Windows Azure Platform 系列文章目录> 我们知道,Azure Virtual Network可以 1.将对台Azure VM加入到同一个网段里,同时绑定内网IP地址 2.创建VPN网关,来设置Site-To-Site VPN或者Point-To-Site VPN 但是我们在使用Virtual Network的时候,会遇到这样的情况: 1.之前创建的2个Virtual Network,本来是互相不能通过内网访问的.但是后期想通过内网互通互联. 2.在创建的Virtual

QC ALM 11创建域、项目和用户

一旦HP-ALM安装,我们仅仅能继续创建域.项目和用户使用后的ALM工作.以下是步骤来创建项目.域和用户.       一.创建域 1.对于创建域,第一步是进入站点管理员页面.开展QC使用URL - http://localhost:8080/qcbin/SiteAdmin.jsp. 并输入被设置在安装QC管理员凭据.例如以下图所看到的:   2.登录到站点后台管理页面后.我们会看到站点项目登陆标签,例如以下图所看到的.下一步是创建一个域. 3.点击在左上角的'创建域'button,然后输入域名

c++11 stl 学习之 shared_ptr

shared_ptr智能指针 shared_ptr 的声明初始化方式由于指针指针使用explicit参数 必须显示声明初始化shared_ptr<string> pNico = new string("nico"); // ERRORshared_ptr<string> pNico{new string("nico")}; // OK 也可以使用make_shared()shared_ptr<string> pNico = mak