在null指针的情况下,删除器的标准行为在shared_ptr和unique_ptr之间是否不同?

Bob*_*ler 30 c++ shared-ptr unique-ptr nullptr c++11

好的,首先是一些可能相关的事情:

我在C++ 11模式下使用Clang 3.1编译器,标准库设置为libc ++.

我正在尝试熟悉C++ 11,并且这样做我遇到的行为似乎很奇怪.它可能是Clang或libc ++的怪癖,但我不能说C++标准,我无法访问其他支持C++ 11的编译器,所以我无法检查它,我搜索了互联网和Stack Overflow在没有发现任何相关的情况下尽我所能......所以我们走了:

当使用shared_ptr/unique_ptr为简单资源实现RAII时,它们的行为似乎与删除时的空指针不同.我意识到通常没有必要删除空指针,但我原本期望这两个STL智能指针之间的行为至少匹配.

对于特定情况,请考虑以下代码:

{
    auto Deleter = [](void *){cout << "It's later!" << endl;};
    shared_ptr<void> spDoSomethingLater(nullptr, Deleter);
    unique_ptr<void, void (*)(void *)> upDoSomethingLater(nullptr, Deleter);
    cout << "It's now!" << endl;
}
Run Code Online (Sandbox Code Playgroud)

我原本期望得到以下输出之一:

a)如果两个删除器都被调用,即使指针为空:

"It's now!"
"It's later!"
"It's later!"
Run Code Online (Sandbox Code Playgroud)

b)如果由于指针为空而未调用任何删除器:

"It's now!"
Run Code Online (Sandbox Code Playgroud)

但我没有观察到这些情况.相反,我观察到:

"It's now!"
"It's later!"
Run Code Online (Sandbox Code Playgroud)

这意味着正在调用一个但不是另一个删除者.经过进一步研究,我发现无论是否包含null值,都会调用shared_ptr的删除器,但只有在不包含空值的情况下才会调用unique_ptr的删除器.

我的问题:这实际上是标准规定的正确行为吗?如果是这样,为什么两种STL类型之间的指定行为会以这种方式不同?如果没有,这是一个我应该向libc ++报告的错误吗?

Jon*_*Jon 28

观察到的行为符合标准.

因为unique_ptr,20.7.1.2.2/2(析构函数效应)说

效果:如果get() == nullptr没有效果.否则 get_deleter()(get()).

因为shared_ptr,20.7.2.2.2/1表示即使它包装空指针也应该调用删除器:

功效:

  • 如果*这是空的或与另一个shared_ptr实例(use_count() > 1)共享所有权 ,则没有副作用.
  • 否则,如果*拥有一个对象p和一个删除器d,d(p)则调用它.
  • 否则,*它拥有一个指针p,并被delete p调用.

这里重要的细节是表达"拥有一个对象p".20.7.2.2/1说:"一个shared_ptr对象是空的,如果它不拥有的指针".20.7.2.2.1/9(相关的构造函数)说它"构造一个shared_ptr拥有对象p和删除者的对象d".

因此,据我所知,该调用在技术上使shared_ptr 自己的空指针,这导致删除被调用.将其与无参数构造函数进行对比,该构造函数被称为shared_ptr" ".

  • @Alf:在shared_ptr中,对象`p`是可转换为`T*`的任何东西.例如,检查§20.7.2.2.1/ 9. (4认同)
  • @Jon:对不起,我错了.`shared_ptr <int> p;`和`shared_ptr <int> p(0);`确实有不同的效果,我试过两个编译器(Visual C++和g ++).谁会砰的一声.我试图删除downvote但是SO不允许这样做; 你能做一点编辑吗? (3认同)

ken*_*ytm 10

是的,这是正确的行为.

§20.7.1.2.2[unique.ptr.single.dtor]/2:

unique_ptr 析构函数

效果:如果get() == nullptr没有效果.否则get_deleter()(get()).

§20.7.2.2.2[util.smartptr.shared.dest]/1:

shared_ptr 析构函数

效果:

  • 如果*this或与另一个shared_ptr实例(use_count() > 1)共享所有权,则没有副作用.
  • 否则,如果*this 拥有一个对象p和一个删除器d,d(p)则被调用.
  • 否则,*this 拥有一个指针p,并p调用delete .

因为shared_ptr是空的,所以应该没有效果?错了,因为提供a指针会使shared_ptr 不为空,即使指针为空.

§20.7.2.2.1[util.smartptr.shared.const]/8-10

shared_ptr 建设者

template<class Y, class D> shared_ptr(Y* p, D d);
template<class Y, class D, class A> shared_ptr(Y* p, D d, A a);
template <class D> shared_ptr(nullptr_t p, D d);
template <class D, class A> shared_ptr(nullptr_t p, D d, A a);
Run Code Online (Sandbox Code Playgroud)

要求: p应可转换为T*....

效果:构造一个shared_ptr该对象拥有的对象p和删除器d.

后置条件: use_count() == 1 && get() == p.

这意味着shared_ptr 拥有 nullptr.因此,当shared_ptr被销毁时将调用deleter.