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 在生成一千万个Any
s 并将它们存储在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` 之间的区别