• c++11 智能指针 (std::shared_ptr)(六)


     定义于头文件 
    template< class T > class shared_ptr;     (C++11 起) 

    构造对象 

    1. std::make_shared,
    2. std::make_shared_default_init

    template< class T, class... Args >
    shared_ptr make_shared( Args&&... args );

    (1)(C++11 起)
    (T 非数组)

    template
    shared_ptr make_shared( std::size_t N );

    (2)(C++20 起)
    (T 为 U[])

    template
    shared_ptr make_shared();

    (3)(C++20 起)
    (T 为 U[N])

    template
    shared_ptr make_shared( std::size_t N, const std::remove_extent_t& u );

    (4)(C++20 起)
    (T 为 U[])

    template
    shared_ptr make_shared( const std::remove_extent_t& u );

    (5)(C++20 起)
    (T 为 U[N])

    template
    shared_ptr make_shared_default_init();

    (6)(C++20 起)
    (T 非 U[])

    template
    shared_ptr make_shared_default_init( std::size_t N );

    (7)(C++20 起)
    (T 为 U[])

     

    1) 以 argsT 的构造函数参数列表,构造 T 类型对象并将它包装于 std::shared_ptr 。对象如同用表达式 ::new (pv) T(std::forward(args)...) 构造,其中 pv 是内部指向适合保有 T 类型对象的存储的 void* 指针。存储典型地大于 sizeof(T) ,以对共享指针控制块和 T 对象使用一次分配。此函数所调用的 std::shared_ptr 构造函数以指向新构造的 T 类型对象指针启用 shared_from_this 。此重载仅若 T 不是数组类型才参与重载决议。

    2,3) 同 (1) ,但构造的对象是可能多维的数组,其 std::remove_all_extents_t 类型的非数组元素如同以布置 new 表达式 ::new(pv) std::remove_all_extents_t() 值初始化。重载 (2) 创建第一维上大小为 N 的数组。数组元素以其地址递增顺序初始化,而当其生存期结束时,以原本构造顺序的逆序销毁。

    4,5) 同 (2,3) ,但每个元素从默认值 u 初始化。若 U 不是数组类型,则这如同以如 (1) 中的布置 new 表达式进行;否则,这如同以如同 (1) 中的布置 new 表达式,从来自 u 的对应元素初始化(可能多维的)数组的每个非数组元素。重载 (4) 创建第一维上大小为 N 的数组。数组元素以其地址递增顺序初始化,而当其生存期结束时,以原本构造顺序的逆序销毁。

    6) 若 T 不是数组类型则同 (1) ,而若 (3) 是 U[N] 则同 if T ,除了默认初始化创建的对象。

    7) 同 (2) ,除了默认初始化单独的数组元素。

    每种情况下,均将用 p->~X() 销毁对象(或若 T 为数组类型则为单独的元素) (C++20 起),其中 p 是指向对象的指针,而 X 是该对象的类型。

    参数

    args-将用以构造 T 实例的参数列表。
    N-要使用的数组
    u-初始化数组每个元素的初值

    返回值

    类型 T 实例的 std::shared_ptr 。

    异常

    可能抛出 std::bad_alloc 或任何 T 构造函数所抛的异常。若抛出异常,则函数无效果。若异常在数组的构造中抛出,则已初始化元素以逆序销毁。 (C++20 起)

    注意

    此函数可用作 std::shared_ptr(new T(args...)) 的替代品。得失是:

    • std::shared_ptr(new T(args...)) 进行至少二次分配(一次为 T 而另一次为共享指针的控制块),而 std::make_shared 典型地仅进行一次分配(标准推荐但不要求如此,所有已知实现均如此)。
    • 若任何 std::weak_ptr 在所有共享拥有者的生存期结束后引用 std::make_shared 所创建的控制块,则 T 所占有的内存维持着,直至所有弱拥有者亦被销毁,若 sizeof(T) 较大则这可能是不想要的。
    • std::shared_ptr(new T(args...)) 可能调用 T 的非公开构造函数,若在它可访问的语境中执行,而 std::make_shared 要求对被选择构造函数的公开访问。
    • 不同于 std::shared_ptr 构造函数, std::make_shared 不允许自定义删除器。
    • std::make_shared 使用 ::new ,故若用类特定的 operator new 设置了任何特殊行为,则它将异于 std::shared_ptr(new T(args...)) 。
    • std::shared_ptr 支持数组类型(从 C++17 起),但 std::make_shared 不支持。 boost::make_shared 支持此功能。
    (C++20 前)
    • 如 f(std::shared_ptr(new int(42)), g()) 的代码可能导致内存泄漏,若 gnew int(42) 后得到调用且抛出异常,而 f(std::make_shared(42), g()) 是安全的,因为二个函数调用决不会穿插。
    (C++17 前)

    构造函数以 U* 类型指针 ptr 启用 shared_from_this ,表示它确定 U 是否拥有作为 std::enable_shared_from_this 特化的无歧义且可访问 (C++17 起)基类,而若如此,则构造函数求值该语句:

    if (ptr != nullptr && ptr->weak_this.expired())
      ptr->weak_this = std::shared_ptr>(*this,
                                      const_cast*>(ptr));

    其中 weak_this 是 std::shared_from_this 的隐藏 mutable std::weak_ptr 成员。对 weak_this 成员的赋值不是原子的,且与任何到同一对象的潜在并发访问冲突。这确保将来对 shared_from_this() 调用,将与此裸指针构造函数所创建的 shared_ptr 共享所有权。

    上述解释代码中,测试 ptr->weak_this.expired() 是为确保若 weak_this 指示已有占有者则重赋值它。从 C++17 起要求此测试。

    调用示例

    1. #include <iostream>
    2. #include <memory>
    3. #include <type_traits>
    4. struct C
    5. {
    6. C(int i) : i(i) {} // < 需要构造函数 (C++20 前)
    7. int i;
    8. };
    9. int main()
    10. {
    11. auto sp = std::make_shared<C>(12);
    12. std::cout << sp->i << '\n';
    13. }

    输出

  • 相关阅读:
    Damask使用指南-Hcp结构(镁(考虑孪晶))孪晶如何加入
    C.打牌的贝贝(卡特兰数)
    GitHub下载量从19暴涨到5W,这份架构师学习路线只用了一晚
    计算机考研面试汇总
    <学习笔记>从零开始自学Python-之-web应用框架Django( 十)通用模板
    Android中EditText的密码显示与隐藏
    vue form设置rules不生效
    【从零开始学习 SystemVerilog】2.4、SystemVerilog 数据类型—— Enumeration(枚举)
    Discuz论坛网站搭建教程,从0开始学会搭建网站
    .NET 部署 多域名 Https(SSL)通过代码方式
  • 原文地址:https://blog.csdn.net/qq_40788199/article/details/126791147