加速访问可能存在的错误

时间:2015-01-16 08:51:51

标签: c++ boost boost-variant

我有以下错误消息:

/usr/include/boost/variant/detail/visitation_impl.hpp:207: typename Visitor::result_type boost::detail::variant::visitation_impl(int, int, Visitor &, VPCV, mpl::true_, NBF, W *, S *) [W = mpl_::int_<20>, S = boost::detail::variant::visitation_impl_step<boost::mpl::l_iter<boost::mpl::l_end>, boost::mpl::l_iter<boost::mpl::l_end> >, Visitor = boost::detail::variant::copy_into, VPCV = const void *, NBF = boost::variant<TypeInfo, int, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_>::has_fallback_type_]: Assertion `false' failed.

当我将std::vector<A>作为参数传递给某个函数并且A定义为using A = boost::variant<B, int>;时,就会发生这种情况。 简单来说,B的定义如下:

class B
{
    Data data;
    std::vector< boost::variant<std::shared_ptr<C>, B> > vec;
};
错误消息中

B TypeInfo

void func(std::vector<B> vec); //signature

auto result = func(that_vector_with_variants); //that line causes an error

我在https://svn.boost.org/trac/boost/ticket/5146

找到了类似的错误

我的问题是:它是助推器中的错误吗?如何使我的代码工作?

更新

我认为我必须补充一点,如果我将std::vector<boost::variant<std::shared_ptr<C>, B> > vec;更改为std::vector<boost::variant<C*, B> > vec;,那么一切正常。

1 个答案:

答案 0 :(得分:3)

走出困境,从阅读错误报告中,你可能无意中做了这样的事情:

#include <iostream>
#include <boost/make_shared.hpp>
#include <boost/variant.hpp>

using P = boost::shared_ptr<int>;
using V = boost::variant<P, int>;
using C = std::vector<V>;

int main() {
    P p = boost::make_shared<int>(42);
    assert(p.unique());

    C v = { p };
    assert(!p.unique());

    v = std::move(v);
    assert(!p.unique()); // WHOOPS assert fails
}

当然这个样本是设计的,因为我不知道你的实际代码/用例。

最后一个断言失败了。这是因为内部操作的顺序是这样的:在分配新值之前清除原始变体(并且包含的​​值被破坏)

  

“永不空”保证

     

虽然永不空洞的保证起初可能看起来“显而易见”,但事实上如何实现它通常并不简单

     

比照。来自Boost Variant“设计概述”的The "Ideal" Solution: False Hopes

所以,如果我们没有对int中的p进行“引用”,则此操作会在重新分配之前销毁该实例。

在这种情况下,它看起来更像是一种使用模式(基本上使用智能指针¹进行就地修改)以避免。在这种特殊情况下,这些似乎可行(在我的编译器/库实现上):

std::move(v.begin(), v.end(), v.begin());
// or
std::copy(std::make_move_iterator(v.begin()), std::make_move_iterator(v.end()), v.begin());
// or
v.assign(std::make_move_iterator(v.begin()), std::make_move_iterator(v.end()));

但我当然更喜欢把它写得更像

C tmp = std::move(v); 
v = std::move(tmp);

仅仅因为没有其他保证。


¹总是有危险!即使Scott Meyers在他的“更有效的C ++”中也有这种感觉,请参阅 erratum p.200/202

²相关:What does the standard library guarantee about self move assignment?