指向不同类的共享指针数组

16 c++ smart-pointers shared-ptr c++11

我试图弄清楚是否可以创建一个指向不同类型的共享指针数组.例如,类似的东西:

vector<shared_ptr<**???**>> v;
v.push_back(shared_ptr<int>(new int));
v.push_back(shared_ptr<MyClass>(new MyClass()));
Run Code Online (Sandbox Code Playgroud)

或任何其他方式通过shared_ptr而不知道其类型.

sfr*_*hse 27

更安全的类型可能是:

/// header #include <boost/variant.hpp>
typedef boost::variant < boost::shared_ptr < T1 >, boost::shared_ptr < T2 >, ... > VariantT;

std::vector < VariantT > container;
container.push_back ( boost::shared_ptr < T1 > ( new T1 ) ); // or boost::make_shared
container.push_back ( boost::shared_ptr < T2 > ( new T2 ) ); // or boost::make_shared
Run Code Online (Sandbox Code Playgroud)

更多介绍一下Boost.Variant库.

  • 请注意,只有在编译时可以约束变量支持的类型时,此方法才有效. (4认同)
  • @bpw:你怎么办?你不能在编译时将一些你不知道的类型转换(并且这总是归结为在某个级别或其他级别进行转换).我可以想到在编译时处理未知类型的唯一方法是运行时多态,它需要相关类型. (4认同)

JBL*_*JBL 22

假设您要存储不继承公共类的对象,最简单的方法是使用boost::any.

您仍然需要确定每个索引存储的每个对象的类型(即能够执行正确的boost::any_cast).

你应该这样做,而不是存储指针void.这是最接近文本正确的方式来存储"你知道类型但编译器没有的东西",这意味着在检索值时使用了强制转换.

虽然两个(any和一个void指针)将以相同的方式(指针旁边)工作,但如果你转换为错误的类型,any将抛出bad_any_cast异常(IIRC),而使用void指针,你将得到未定义的行为.对coliru的简单尝试产生了一个段错误.

  • 实际上,你会得到它未定义的行为.如果你很幸运的话,这显示为段错误. (6认同)
  • `boost :: any`不是类模板,它是一个类. (5认同)
  • 好吧,你可以试着为它实现一个解决方案,但我认为它最终会像`boost :: any`一样.哦,"boost :: any"是一个仅限标题的提升功能,因此甚至没有必须链接到额外的lib的论点. (2认同)

Cas*_*sey 5

正如任何基本指针类型都可以转换为void*,任何shared_ptr将转换为shared_ptr<void>:

vector<shared_ptr<void>> v;
v.push_back(make_shared<int>());
v.push_back(make_shared<MyClass>());
Run Code Online (Sandbox Code Playgroud)

您现在拥有一个vector完全类型擦除的共享指针.然而,你无法做任何有趣的事情:你必须知道哪些类型存储在vector转换它们的哪些插槽中:

auto intptr = static_pointer_cast<int>(v[0]);
auto myclass_ptr = static_pointer_cast<MyClass>(v[1]);
Run Code Online (Sandbox Code Playgroud)

因此虽然可以做到这一点,但它并不是非常有用,可能表明设计已经破损.

  • 不,这不是你想要的.通过`void*`的通用性很糟糕,会导致你编写___buggy,难以修复,难以维护的代码___.许多C++的构造都是为了摆脱这种古老的C习惯而发明的.[sfrehse的回答](http://stackoverflow.com/a/26844776/140719)更好. (21认同)
  • 好吧,我在这里学到了一些东西 不知道这个伎俩是可能的.当然,我现在必须确保我永远不会在我自己的代码中做一些愚蠢的事情.Satus - 请听大家告诉你这是一个破碎的设计.你将惯用的C与惯用的C++混合在一起,唯一的结果就是脆弱的代码. (3认同)
  • @Satus - 通过完全删除类型信息(在`void*`解决方案中),您将失去安全性,表现力和性能.安全,因为没有检查你拔出正确的类型.`variant`或`any`类是*区分*联合,也就是说,它*记住并检查*它的类型.表达性失去了,因为它可能是*任何*,这是危险的,而不是自我记录.效率会丢失,因为编译器无法再根据类型信息进行优化.有区别的联合不如实际类型好,但它比`void*`更好.不要使用这个解决方案! (3认同)
  • @Satus - 实际上这完全不是真的.我教,我在办公时间看到这一点,潜在的错误是非确定性的,因为有时候你得到的垃圾就足够接近你所需的工作了.如果你用valgrind运行程序,你*可能*在第一次运行时捕获它.我还没有看到你对这种糟糕方法的承诺中的任何实质内容,只有懒惰. (3认同)
  • @Satus:我说_"你不想这样做,因为它导致代码有问题,难以修复,难以维护."_你问为什么你不想这样做?我不知道该怎么回答. (2认同)