【问题标题】:Possible bug in boost visitation提升访问中可能存在的错误
【发布时间】:2015-03-14 20:02:57
【问题描述】:

我收到以下错误消息:

/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&lt;A&gt; 作为参数按值传递给某个函数并且A 被定义为using A = boost::variant&lt;B, int&gt;; 时,就会发生这种情况。 简单来说,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发现了类似的错误

我的问题是:这是 boost 中的错误吗?我怎样才能使我的代码工作?

更新:

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

【问题讨论】:

  • 访客是什么?您没有显示任何相关代码。您正在使用变体。在一个容器中。好的。这基本上就是我们现在所知道的全部
  • @sehe,这是主要问题,它是一些内部访问者。当我在 gdb 中查看回溯时,我发现在复制向量时出现了错误。

标签: c++ boost boost-variant


【解决方案1】:

走投无路,通过阅读该错误报告,您可能无意中做了这样的事情:

#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
}

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

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

“永不空”保证

虽然从不为空的保证一开始可能看起来“显而易见”,但实际上通常如何实现它甚至都不是直截了当的

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

所以,如果我们没有在 p 中对 int 的“引用”,那么此操作会在实例被重新分配之前将其销毁。

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

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?

【讨论】:

  • 顺便说一句,std::move(v.begin(), v.end(), v.begin()); 是什么?没有这样的过载。
  • 糟糕。我从来不知道。谢谢你又教了我一些新东西。
猜你喜欢
  • 2013-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-29
  • 2018-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多