【问题标题】:Why does unique_ptr overload reset(pointer p = pointer()) and reset(nullptr_t)?为什么 unique_ptr 重载 reset(pointer p = pointer()) 和 reset(nullptr_t)?
【发布时间】:2014-06-23 05:53:38
【问题描述】:

根据http://en.cppreference.com/w/cpp/memory/unique_ptr/reset

void reset( pointer ptr = pointer() );

template< class U > 
void reset( U ) = delete;

void reset( std::nullptr_t p );

1) 给定current_ptr,由*this 管理的指针执行 按此顺序执行以下操作: 保存当前指针old_ptr = current_ptr的副本; 用参数current_ptr = ptr 覆盖当前指针; 如果旧指针非空,则删除之前管理的对象if(old_ptr != nullptr) get_deleter()(old_ptr)

2) 在动态数组的特化中,std::unique_ptr&lt;T[]&gt;, 提供此模板成员是为了防止将 reset() 与 指向派生的指针(这将导致未定义的行为 数组)。

3) 在动态数组的特化中,std::unique_ptr&lt;T[]&gt;, 第三次重载是必要的,以允许重置为nullptr(这将 否则被模板重载禁止)。相当于 reset(pointer())

既然reset(nullptr)等价于reset(pointer()),那为什么还存在后者呢?

如果我想重置一个数组形式的 unique_ptr,为什么不能只使用rest(pointer())

【问题讨论】:

  • 我实际上发现deleteion 的方法更有趣...
  • 因为p.reset(nullptr) 是一个编译错误会很愚蠢?
  • 请注意,std::unique_ptr&lt;T[]&gt; 仅接受 T *T * 作为其构造函数和 reset 方法的指针类型。值得注意的是,它不接受指向不同于T 的类型的指针,即使它们可以转换为指向T 的指针。换句话说:没有那个重载p.reset(nullptr); 将无法编译。那将是非常愚蠢的。 (出于同样的原因,有一个unique_ptr(nullptr_t) ctor。)

标签: c++ arrays c++11 overloading unique-ptr


【解决方案1】:

template< class U > 
void reset( U ) = delete;

将被选择用于带有nullptr 参数的调用,如果不是用于

void reset( std::nullptr_t p );

这就是它存在的原因,允许使用nullptr 调用。


示例(使用FIX 进行编译以抑制编译错误):

#include <cstddef>      // std::nullptr_t

struct S
{
    void reset( char* ) {}

    template< class Type >
    void reset( Type ) = delete;

    #if FIX
    void reset( std::nullptr_t ) {}
    #endif
};

auto main() -> int
{
    S().reset( nullptr );    // Fails when FIX is not defined.
}

【讨论】:

  • 为什么reset(nullptr)不能解析为reset(pointer)? #1 形式比 #2 形式更具体。所以,我认为,即使没有#3 形式,重载决议仍然可以工作。
  • @xmllmx:模板在类型上完全匹配,而非模板涉及转换。
【解决方案2】:

resetist 实现为

pointer old = this->ptr;
this->ptr= newPointer;
delete[] old;

删除数组的模板化重载,防止出现以下情况

class foo{};
class bar : public foo {};

foo* managedPointer = new foo[3];
bar* newPointer = new bar[5];

foo* old = managedPointer;
managedPointer = newPointer;
delete[] old;

这是未定义的行为。第 5.3.5 节第 3 段:

[...] 在第二种选择(删除数组)中,如果要删除的对象的动态类型与其静态类型不同,则行为未定义。

由于删除的函数仍然参与重载解析,并且reset(U)nullptr 提供比reset(pointer) 更好的匹配 ,还有一个额外的重载允许reset(nullptr),否则会导致编译器错误,从而导致数组和指针版本之间的接口不一致。

【讨论】:

    猜你喜欢
    • 2021-05-30
    • 1970-01-01
    • 1970-01-01
    • 2012-12-01
    • 2019-09-29
    • 1970-01-01
    • 2018-07-29
    • 1970-01-01
    • 2017-03-03
    相关资源
    最近更新 更多