为什么std :: unique_ptr没有隐式转换为T *和const T *?

时间:2016-02-15 12:58:15

标签: c++ c++11

如果我自己写,我想我会做的事情如下:

template<typename T, typename Dtor = std::default_delete<T> >
class Uptr : private Dtor {
  T* vl_;
public:
  explicit Uptr(T* vl = nullptr) noexcept : vl_(vl) {}
  ~Uptr() noexcept { Dtor::operator()(vl_); }

  Uptr& swap(Uptr& o) noexcept { T* tmp; tmp = vl_; vl_=o.vl_; o.vl_ = tmp; }

  Uptr& operator=(Uptr&& o) noexcept { o.swap(*this); }
  Uptr& operator=(nullptr_t) noexcept { vl_=nullptr; return *this; } 
  Uptr(Uptr&& o) noexcept : Uptr(nullptr) { *this = std::move(o); } 

  Uptr(const Uptr& o) = delete;
  Uptr& operator=(const Uptr& o) = delete;


  operator T*() noexcept { return vl_; } 
  operator const T*() const noexcept { return vl_; } 

  T* release() noexcept { T* ret = vl_; vl_=nullptr; return ret; }    

  const Dtor& deleter() const noexcept { return *(static_cast<Dtor*>(this)); }
  Dtor& deleter() noexcept { return *(static_cast<Dtor*>(this)); }
};

并且不必定义get()和运算符*->[]

在这种情况下进行隐式转换有什么问题?

3 个答案:

答案 0 :(得分:14)

我认为你的问题不是unique_ptr特有的,而是一般地询问智能指针。

Herb Sutter wrote about this a long time ago。显然,它允许您编写逻辑错误的代码,例如:

unique_ptr<something> p;
...
delete p; // p is a smart pointer - probably not what you want.

和其他类似的代码。

答案 1 :(得分:8)

正如其他人所指出的那样,可能会发生一些恼人的错误,例如

T* f() { unique_ptr p{...}; return p; } // oops

unique_ptr p{...}; delete p; // oops

unique_ptr get_up();

shared_ptr sp{get_up()}; // cool, this works: promote UP to SP

// does it work the other way around?

shared_ptr get_sp();

unique_ptr p{get_sp()}; // compiles, then yes! eh, wait.. BOOM!

等等。考虑到这种语言是为人类设计的,它通过在这种情况下使一切都明确来避免这些陷阱,这样更安全。

答案 2 :(得分:6)

我没有正式答案,但我知道为什么这没有多大意义。 unique_ptr的整个想法是一种强类型(即编译器强制执行)的方式来承载对象的唯一所有权。因此移动语义。

在这种情况下,让unique_ptr要求您明确请求其原始指针是有意义的,因为只要您拥有原始值,就可以轻松地破坏所有内容:您可以delete它,你可以将它传递给另一个智能指针(它会在某个时刻删除它),或者做指针算术并意外地处理结果(可能不指向已分配的内存)或类似的东西。其中一些可能会立即导致编译器错误,其他可能导致未定义的行为。对于像unique_ptr这样的高级类,这是不可取的,至少不是这个隐含的。当然,您可以使用.get()执行相同操作,但在这种情况下,您知道您正在使用原始指针值,并且您不能释放它。

link posted by Ami也很相关,但我认为另一个例子更好引用:

unique_ptr p( new widget );
...
use( p + 42 ); // error (maybe he meant "*p + 42"?)
    // but if implicit conversion to * were allowed, would silently compile -- urk

C ++哲学是可以在给定类型上运行的公共函数属于该类型的接口。控制和限制隐式转换为指针的类型的接口实际上是不可能的。智能指针的故意限制性质将被完全解构,导致容易出错的代码。

相关问题