c++ - unique_ptr 的动态转换

标签 c++ casting c++11 smart-pointers unique-ptr

与 Boost 中的情况一样,C++11 提供了一些用于转换 shared_ptr 的函数:

std::static_pointer_cast
std::dynamic_pointer_cast
std::const_pointer_cast

然而,我想知道为什么没有 unique_ptr 的等效函数。

考虑以下简单示例:

class A { virtual ~A(); ... }
class B : public A { ... }

unique_ptr<A> pA(new B(...));

unique_ptr<A> qA = std::move(pA); // This is legal since there is no casting
unique_ptr<B> pB = std::move(pA); // This is not legal

// I would like to do something like:
// (Of course, it is not valid, but that would be the idea)
unique_ptr<B> pB = std::move(std::dynamic_pointer_cast<B>(pA));

是否有任何理由不鼓励这种使用模式,因此没有为 unique_ptr 提供与 shared_ptr 中存在的功能等效的功能?

最佳答案

除了 Mark Ransom 的 answer , 一个 unique_ptr<X, D>甚至可能不会存储 X* .

如果删除器定义类型 D::pointer那么这就是存储的内容,可能不是真正的指针,它只需要满足NullablePointer要求和(如果调用 unique_ptr<X,D>::get())有 operator*返回 X& ,但不要求支持转换为其他类型。

unique_ptr非常灵活,不一定表现得非常像内置指针类型。

根据要求,这是一个存储类型不是指针的示例,因此无法进行强制转换。这有点做作,但在 C++ RAII 风格的 API 中包装了一个虚构的数据库 API(定义为 C 风格的 API)。 OpaqueDbHandle 类型符合 NullablePointer需求,但只存储一个整数,用作通过一些实现定义的映射查找实际数据库连接的键。我并不是把它作为一个伟大设计的例子,只是作为一个使用 unique_ptr 的例子。管理非动态分配指针的不可复制、可移动资源,其中“删除器”不只是调用析构函数并在 unique_ptr 时释放内存超出范围。

#include <memory>

// native database API
extern "C"
{
  struct Db;
  int db_query(Db*, const char*);
  Db* db_connect();
  void db_disconnect(Db*);
}

// wrapper API
class OpaqueDbHandle
{
public:
  explicit OpaqueDbHandle(int id) : id(id) { }

  OpaqueDbHandle(std::nullptr_t) { }
  OpaqueDbHandle() = default;
  OpaqueDbHandle(const OpaqueDbHandle&) = default;

  OpaqueDbHandle& operator=(const OpaqueDbHandle&) = default;
  OpaqueDbHandle& operator=(std::nullptr_t) { id = -1; return *this; }

  Db& operator*() const;

  explicit operator bool() const { return id > 0; }

  friend bool operator==(const OpaqueDbHandle& l, const OpaqueDbHandle& r)
  { return l.id == r.id; }

private:
  friend class DbDeleter;
  int id = -1;
};

inline bool operator!=(const OpaqueDbHandle& l, const OpaqueDbHandle& r)
{ return !(l == r); }

struct DbDeleter
{
  typedef OpaqueDbHandle pointer;

  void operator()(pointer p) const;
};

typedef std::unique_ptr<Db, DbDeleter> safe_db_handle;

safe_db_handle safe_connect();

int main()
{
  auto db_handle = safe_connect();
  (void) db_query(&*db_handle, "SHOW TABLES");
}


// defined in some shared library

namespace {
  std::map<int, Db*> connections;      // all active DB connections
  std::list<int> unused_connections;   // currently unused ones
  int next_id = 0;
  const unsigned cache_unused_threshold = 10;
}

Db& OpaqueDbHandle::operator*() const
{
   return connections[id];
}

safe_db_handle safe_connect()
{
  int id;
  if (!unused_connections.empty())
  {
    id = unused_connections.back();
    unused_connections.pop_back();
  }
  else
  {
    id = next_id++;
    connections[id] = db_connect();
  }
  return safe_db_handle( OpaqueDbHandle(id) );
}

void DbDeleter::operator()(DbDeleter::pointer p) const
{
  if (unused_connections.size() >= cache_unused_threshold)
  {
    db_disconnect(&*p);
    connections.erase(p.id);
  }
  else
    unused_connections.push_back(p.id);
}

关于c++ - unique_ptr 的动态转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11002641/

相关文章:

c++ - DeleteFile() 失败但文件存在(文件名很长)

c++ - 如何在C++中修复 “No viable overloaded ' =' ”

c++ - 从没有奇点的矩阵中获取俯仰和滚动

swift - 快速从发件人那里获取 UIImage

c++ - 为什么 new 没有用模板实现?

c++ - 每个类型的多实例计数器

在 C 中将 const void * 转换为 const char *

java - 如何在 Java 中从另一个包中转换出同一类的类型?

c++ - 这段代码安全吗,是否可以从构造函数 C++ 生成线程?

c++ - 为什么这个无锁堆栈类中的 'deleting' 节点会导致竞争条件?