在C ++中,空std :: shared_ptr和空std :: shared_ptr有什么区别?


80

cplusplus.comshared_ptr页面召唤出一个区分 std::shared_ptr shared_ptr。该cppreference.com页面没有明确叫出区别,但同时使用“空”,并比较nullptr其描述std::shared_ptr行为。

空和空值之间有区别shared_ptr吗?这种混合行为指针有什么用例?非空nullshared_ptr甚至有意义吗?在正常使用情况下(如果您没有显式构造一个)会出现一个空但非空的情况shared_ptr吗?

如果您使用的是Boost版本而不是C ++ 11版本,这些答案是否会改变?

Answers:


80

这是shared_ptr行为的一个怪异角落。它有一个构造函数,可以让你做出shared_ptr拥有的东西,别的东西:

template< class Y > 
shared_ptr( const shared_ptr<Y>& r, T *ptr );

shared_ptr使用此构造函数的构造方法与共享所有权r,但指向任何ptr指向的点(即,调用get()operator->()将返回ptr)。这对于ptr指向拥有的对象的子对象(例如,数据成员)的情况非常方便r

你的页面链接的电话shared_ptr拥有没什么,并且shared_ptr它指向什么(即它的get() == nullptr。(标准在这种意义上使用Empty;不使用null。)您可以构造一个null-not-not-empty shared_ptr,但它不是很有用。空但shared_ptr非空本质上是一个非所有的指针,它可以用来做一些奇怪的事情,例如将指向分配给堆栈的东西的指针传递给期望a的函数shared_ptr(但我建议对放置shared_ptr在其中的任何对象进行打孔API)。

boost::shared_ptr有这个构造器,他们称之为别名构造器


8
值得注意的是:C ++ 11§20.7.2.2.1(p16) “注意:此构造函数允许shared_ptr使用非NULL存储的指针创建空实例。” 同样值得一提的是前面的注释(p15),“为避免指针悬空的可能性,此构造函数的用户必须确保p至少在r销毁所有权之前,该保持有效。” 确实很少使用的构造。
WhozCraig 2014年

@Cubbi A shared_ptr,无论是否拥有任何东西,其get()回报nullptr 的确等于nullptr
TC

3
空,但非空shared_ptr小号可以是有用的,以确保某些功能被执行一次全部拥有指针的范围耗尽(甚至在例外情况下!)。不确定,现在是否有一个特殊的类。
coldfix 2014年

@coldfix非空非空不能shared_ptr做的空但非空能做shared_ptr什么?
TC

2
别名构造器源自彭博社,并在Boost中实现之前就已针对该标准提出(见N1851)。我更喜欢标准的术语“与……共享所有权r”,而不是措辞“拥有任何东西r
Jonathan Wakely 2015年

9

空shared_ptr和空shared_ptr之间有区别吗?

shared_ptr没有控制块,其使用计数被认为是0。空副本shared_ptr是另一个空shared_ptr。它们都是独立shared_ptr的,不共享公共控制块,因为它们没有共享控制块。shared_ptr可以使用默认构造函数或采用的构造函数来构造Empty nullptr

非空nullshared_ptr具有可与其他共享的控制块shared_ptr。非空null的副本shared_ptrshared_ptr与原始副本共享相同的控制块,shared_ptr因此使用计数不为0。可以说所有副本均shared_ptr共享相同nullptr。非空nullshared_ptr可以使用对象类型(不是nullptr)的null指针构造

这是示例:

#include <iostream>
#include <memory>

int main()
{
    std::cout << "std::shared_ptr<int> ptr1:" << std::endl;
    {
        std::shared_ptr<int> ptr1;
        std::cout << "\tuse count before copying ptr: " << ptr1.use_count() << std::endl;
        std::shared_ptr<int> ptr2 = ptr1;
        std::cout << "\tuse count  after copying ptr: " << ptr1.use_count() << std::endl;        
        std::cout << "\tptr1 is " << (ptr1 ? "not null" : "null") << std::endl;
    }
    std::cout << std::endl;

    std::cout << "std::shared_ptr<int> ptr1(nullptr):" << std::endl;
    {
        std::shared_ptr<int> ptr1(nullptr);
        std::cout << "\tuse count before copying ptr: " << ptr1.use_count() << std::endl;
        std::shared_ptr<int> ptr2 = ptr1;
        std::cout << "\tuse count  after copying ptr: " << ptr1.use_count() << std::endl;        
        std::cout << "\tptr1 is " << (ptr1 ? "not null" : "null") << std::endl;
    }
    std::cout << std::endl;

    std::cout << "std::shared_ptr<int> ptr1(static_cast<int*>(nullptr))" << std::endl;
    {
        std::shared_ptr<int> ptr1(static_cast<int*>(nullptr));
        std::cout << "\tuse count before copying ptr: " << ptr1.use_count() << std::endl;
        std::shared_ptr<int> ptr2 = ptr1;
        std::cout << "\tuse count  after copying ptr: " << ptr1.use_count() << std::endl;        
        std::cout << "\tptr1 is " << (ptr1 ? "not null" : "null") << std::endl;
    }
    std::cout << std::endl;

    return 0;
}

它输出:

std::shared_ptr<int> ptr1:
    use count before copying ptr: 0
    use count  after copying ptr: 0
    ptr1 is null

std::shared_ptr<int> ptr1(nullptr):
    use count before copying ptr: 0
    use count  after copying ptr: 0
    ptr1 is null

std::shared_ptr<int> ptr1(static_cast<int*>(nullptr))
    use count before copying ptr: 1
    use count  after copying ptr: 2
    ptr1 is null

http://coliru.stacked-crooked.com/a/54f59730905ed2ff


1
我认为这更好地回答了为什么我们必须在shared_ptr的自定义删除程序中检查null的原因。在shared_ptr的自定义删除器中检查nullptr是否有意义?
David Lee
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.