为什么我们可以在null shared_ptr上调用reset?

时间:2016-11-01 08:26:36

标签: c++ shared-ptr smart-pointers

C++ primer显示了一个示例:

        auto &nos = result[word]; 
        if (!nos) nos.reset(new std::set<int>);

结果为std::map<string, shared_ptr<std::set<int>>>

我的问题是:如果!nos成立,nos是否为空?那为什么我们可以在此reset上调用shared_ptr方法?

5 个答案:

答案 0 :(得分:4)

是的,它是空的,在中它没有指向任何数据意义,但它仍然是有效的shared_ptr对象。在示例代码中,您使用有效指针重新设置它。

或者,你可以这样写:

auto &nos = result[word]; 
if (!nos) nos = std::make_shared<std::set<int>>();

答案 1 :(得分:2)

任何智能指针都是原始指针的包装器。如果你让事情变得非常简单,那么智能指针可能看起来像这样:

template< class T >
class some_smart_ptr
{
public:
    <...>
    void reset(T * ptr)
    {
        delete _data; // possibly
        _data = ptr;
    }

    operator bool()
    {
        return _data == nullptr;
    }

    T * operator->()
    {
        return _data;
    }

    <...>

private:
    T * _data = nullptr;
};

正如您所看到的,它有一个指向数据的内部原始指针,以及用于访问数据的重载operator->。 reset函数获取它作为参数获取的指针的所有权,可能删除先前存储在_data的对象(例如,当没有其他共享指针指向同一{{1}时,它发生的共享指针}})。

如果也有重载_data,那么可以在条件中使用它。在这种情况下,它只检查智能指针是否指向任何有意义的东西。如您所见,operator bool为null并不会阻止您使用智能指针本身。

_data

答案 2 :(得分:1)

基本上 shared_ptr operator bool overload

所以这是检查 shared_ptr 是否存储非空指针。

答案 3 :(得分:0)

在此代码中:

    auto &nos = result[word]; 
    if (!nos) nos.reset(new std::set<int>);

nos的类型为std::shared_ptr<std::set<int>>&,因此nos不为空,实际上不能为空。

if (!nos)会致电if (!nos.operator bool())(请参阅std::shared_ptr::operator bool ),这会检查nos是否持有nullptr。如果它保持nullptr,则将其重置为有效指针。

注意,您可以看到nos.reset(new std::set<int>);member-of-object运算符,而不是member-of-pointer运算符。请参阅Member access operators

std::shared_ptr中,member-of-pointer运算符被这个实现所覆盖:

T * operator->()
{
    return /* the raw pointer */;
}

答案 4 :(得分:0)

鉴于

result = std::map<std::string, std::shared_ptr<std::set<int>>>;

然后operator[]()在这一行:

auto &nos = result[word];

给我们提及

  • (如果result包含word)对现有共享指针的引用,或
  • (如果result不包含word)新的默认构造的共享指针。

在第二种情况下,默认构造的共享指针不管理任何对象,其operator bool()返回false。这可以称为智能指针。在这种情况下,下一行将其设置为指向新构造的集合,以便具有相同参数的后续operator[]()将返回非空指针:

if (!nos)
    nos.reset(new std::set<int>);

reset()方法的操作是:

  1. 如果指针已经拥有一个对象,并且是拥有它的最后一个shared_ptr,那么将其删除。 (我们从if (!nos)知道这个指针尚未拥有一个对象,所以在这一步中没有任何反应。)
  2. 将拥有的对象设置为提供的参数。 (在这种情况下,这是新构造的std::set。当它的最后一个共享指针被销毁时,将使用delete销毁它。)
  3. 关于此代码的几点说明:

    • 从摘录中您已经发布了为什么代码需要共享指针的间接,而不是简单地将result简化为std::map<std::string, std::set<int>>
    • 创建一个空的共享指针,然后将其重置为指向一个新对象,可能会比使用std::make_shared()创建一个共享指针的数据位置更差,因为没有机会组合对象的分配和指针的控制结构