std::any 由 std::exception_ptr

Posted

技术标签:

【中文标题】std::any 由 std::exception_ptr【英文标题】:std::any by std::exception_ptr 【发布时间】:2015-12-21 08:13:48 【问题描述】:

可能我不是第一个发现std::exception_ptr 可用于实现any 类型(性能考虑暂且不提)的人,因为它可能是C++ 中唯一可以容纳任何东西的类型。然而,谷歌搜索并没有在这个方向上带来任何结果。

有人知道以下方法是否已用于任何有用的地方吗?

#include <exception>
#include <iostream>

struct WrongTypeError : std::exception  ;

class Any 
public:
   template <class T>
   void set (T t) 
      try  throw t; 
      catch (...)  m_contained = std::current_exception(); 
   

   template <class T>
   T const & get () 
      try  std::rethrow_exception (m_contained); 
      catch (T const & t)  return t; 
      catch (...)  throw WrongTypeError ; 
   

private:
   std::exception_ptr m_contained = nullptr;
;

int main () 
    auto a = Any ;
    a.set (7);
    std::cout << a.get<int> () << std::endl;

    a.set (std::string "Wonderful weather today");
    std::cout <<  a.get<std::string> () << std::endl;
    return 0;

【问题讨论】:

我已经编辑了代码。我认为它不再切片了。 g++ 4.8.4 在生成一千万个Anys 并将它们存储在vector 中没有问题。然而,它非常缓慢。 (设置和获取这 1000 万个值需要 30 秒。) 实际上,我一直认为更好的技巧(因为它从 C++98 开始可用)是使用std::locale,将您想要的任何内容存储为方面。 【参考方案1】:

因为它可能是 C++ 中唯一可以容纳任何东西的类型。

恐怕情况并非如此。 boost::any 可以保存任何类型,甚至可以正确复制(假设该类型是可复制的)它。它是使用一个基类和一个模板化的子类来实现的(广义地说):

class any_base 
  ...


template <class T>
class any_holder : public any_base

 private:
  T m_data;

由此您可以想象您可以将任何类型填充到 any_holder(使用正确的接口),然后您可以通过指向 any_base 的指针来保存 any_holder。这种技术是一种类型擦除;一旦我们有了一个 any_base 指针,我们就持有一个对象,但对类型一无所知。您可以说这是完全类型擦除,例如 std::function 提供部分类型擦除(并且可能在后台使用类似的技术,我不确定是不是在我的脑海中)。

boost::any 提供了额外的接口来支持它使用任何类型,并且它可能提供更好的性能,因为抛出异常非常慢。此外,正如我之前提到的,它正确地复制了底层对象,这非常酷。 exception_ptr 是一个共享所有权指针,所以我相信它会生成浅拷贝。

提升任何网站:http://www.boost.org/doc/libs/1_59_0/doc/html/any.html

我认为它正在被考虑为标准:http://en.cppreference.com/w/cpp/experimental/any

似乎实现类似于 boost,但增加了一个小对象优化。

就我所知,exception_ptr 是一个相当奇怪的野兽,我之前遇到过它并用谷歌搜索过它,那里的信息非常少。但是我很确定它很神奇,即它不能在用户空间中实现。我这样说是因为当你抛出它时,该类型似乎会神奇地取消自身擦除,这通常是不可能的。

【讨论】:

这就是我制作“any”的方式,尽管实际上该机制很简单,可以仅使用 void* 和 const type_info& 来实现,但是如果需要,您必须存储析构函数适当的清理。【参考方案2】:

你肯定是我遇到的第一个想到它的人。

你的横向思维能力给我留下了深刻的印象:)

但是,这种方法存在问题(除了明显的性能问题)。

这源于允许 throw 复制所抛出对象的事实。

首先,这限制了您可以在“任何”类中存储的内容,其次,它会对性能产生进一步影响,第三,每次访问对象时,编译器都没有义务为您提供相同的对象。可以给你一份副本。这意味着至少您应该只以这种方式存储不可变对象。 (注意:当我说“应该”时,我的意思是“绝对不应该!”):)

您可以通过创建一个分配内存来存储对象、记录它的类型并正确删除它的类来解决这个问题...但是如果您这样做了,那么您最好不要出现异常并发症。

无论如何,这就是 boost::any 在幕后所做的。

【讨论】:

“你的横向思维能力给我留下了深刻的印象”——我不能投票两次,可以吗?

以上是关于std::any 由 std::exception_ptr的主要内容,如果未能解决你的问题,请参考以下文章

是否可以仅从 std::any 使用 std::reference_wrapper 创建 std::any?

带有 std::any 和 std::optional 的 any_cast

`boost::any` 和 `std::any` 之间的区别

为啥在 dlopen'd 函数中传递的 std::any 的 std::any_cast 会引发错误

我啥时候应该使用 std::any

std::any - 为啥它缺少这么多运算符?