增加访问量中可能存在的错误
Possible bug in boost visitation
我收到以下错误消息:
/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
我的问题是:这是boost中的错误吗?我怎样才能使我的代码工作?
更新:
我认为我必须补充一点,如果我将 std::vector<boost::variant<std::shared_ptr<C>, B> > vec;
更改为 std::vector<boost::variant<C*, B> > vec;
那么一切正常。
走出困境,通过阅读该错误报告,您可能无意中做了这样的事情:
#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
}
当然这个样本是人为的²,因为我不知道你的实际 code/use 案例。
最后一个断言失败。这是因为在内部,操作的顺序是这样的:原始变体被清除(并且包含的值被破坏)在分配新值之前:
"Never-Empty" Guarantee
While the never-empty guarantee might at first seem "obvious," it is in fact not even straightforward how to implement it in general
Cf. The "Ideal" Solution: False Hopes from Boost Variant "Design Overview"
因此,如果 p
中的 int
没有 "reference",此操作将在实例重新分配之前将其销毁。
在这种情况下,它看起来更像是一种需要避免的使用模式(本质上是使用智能指针进行就地修改 ¹)。在这种特殊情况下,这些似乎有效(在我的 compiler/library 实施中):
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 在他的 "More Effective C++" 中也感受到了这一点,参见 erratum p.200/202
² 相关:What does the standard library guarantee about self move assignment?
我收到以下错误消息:
/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
我的问题是:这是boost中的错误吗?我怎样才能使我的代码工作?
更新:
我认为我必须补充一点,如果我将 std::vector<boost::variant<std::shared_ptr<C>, B> > vec;
更改为 std::vector<boost::variant<C*, B> > vec;
那么一切正常。
走出困境,通过阅读该错误报告,您可能无意中做了这样的事情:
#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
}
当然这个样本是人为的²,因为我不知道你的实际 code/use 案例。
最后一个断言失败。这是因为在内部,操作的顺序是这样的:原始变体被清除(并且包含的值被破坏)在分配新值之前:
"Never-Empty" Guarantee
While the never-empty guarantee might at first seem "obvious," it is in fact not even straightforward how to implement it in general
Cf. The "Ideal" Solution: False Hopes from Boost Variant "Design Overview"
因此,如果 p
中的 int
没有 "reference",此操作将在实例重新分配之前将其销毁。
在这种情况下,它看起来更像是一种需要避免的使用模式(本质上是使用智能指针进行就地修改 ¹)。在这种特殊情况下,这些似乎有效(在我的 compiler/library 实施中):
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 在他的 "More Effective C++" 中也感受到了这一点,参见 erratum p.200/202
² 相关:What does the standard library guarantee about self move assignment?