C++ 共享所有权(std :: shared_ptr)
示例
类模板std::shared_ptr定义了一个共享指针,该共享指针能够与其他共享指针共享对象的所有权。这与std::unique_ptr代表专有所有权相反。
共享行为是通过一种称为引用计数的技术来实现的,其中将指向对象的共享指针的数量存储在对象旁边。当此计数达到零时(通过销毁或重新分配最后一个std::shared_ptr实例),该对象将自动销毁。
//创建:“firstShared”是“Foo”新实例的共享指针 std::shared_ptr<Foo> firstShared = std::make_shared<Foo>(/*args*/);
要创建共享同一对象的多个智能指针,我们需要创建另一个shared_ptr别名作为第一个共享指针的别名。这有两种方法:
std::shared_ptr<Foo> secondShared(firstShared); //第一种方式:复制构造 std::shared_ptr<Foo> secondShared; secondShared = firstShared; //第二种方式:分配
上述任何一种方法,使secondShared一个共享指针,我们的情况下持有股票的Foo有firstShared。
智能指针就像原始指针一样工作。这意味着,您可以*用来取消引用它们。常规->运算符也可以正常工作:
secondShared->test(); //调用Foo::test()
最后,当最后一个别名shared_ptr超出范围时,将Foo调用我们实例的析构函数。
警告:当需要分配用于共享所有权语义的额外数据时,构造ashared_ptr可能会引发bad_alloc异常。如果向构造函数传递了常规指针,则它假定拥有所指向的对象,并在引发异常时调用删除程序。这意味着如果分配失败,将不会泄漏对象。但是,建议使用或,它们使实现能够优化内存分配。shared_ptr<T>(newT(args))Tshared_ptr<T>make_shared<T>(args)allocate_shared<T>(alloc,args)
使用shared_ptr分配数组([])
不幸的是,没有直接的方法使用分配数组make_shared<>。
可以shared_ptr<>使用new和创建数组std::default_delete。
例如,要分配10个整数的数组,我们可以将代码编写为
shared_ptr<int> sh(new int[10], std::default_delete<int[]>());
std::default_delete在此处必须进行指定,以确保使用正确清除了分配的内存delete[]。
如果我们在编译时知道大小,则可以这样进行:
template<class Arr> struct shared_array_maker {}; template<class T, std::size_t N> struct shared_array_maker<T[N]> { std::shared_ptr<T> operator()const{ auto r = std::make_shared<std::array<T,N>>(); if (!r) return {}; return {r.data(), r}; } }; template<class Arr> auto make_shared_array() -> decltype( shared_array_maker<Arr>{}() ) { return shared_array_maker<Arr>{}(); }
然后make_shared_array<int[10]>返回一个shared_ptr<int>指向所有默认构造的10个整数的指针。
使用C++17,shared_ptr获得了对数组类型的特殊支持。不再需要显式指定数组派发器,并且可以使用[]数组索引运算符取消引用共享指针:
std::shared_ptr<int[]> sh(new int[10]); sh[0] = 42;