2015-01-16 2 views
2

У меня есть следующее сообщение об ошибке:Возможная ошибка в повышающем посещении

/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

Мой вопрос: Является ли это ошибка в импульс? Как я могу заставить свой код работать?

Update:

Я думаю, что я должен добавить, что если я изменю std::vector<boost::variant<std::shared_ptr<C>, B> > vec; в std::vector<boost::variant<C*, B> > vec; то все работает.

+0

Что посетитель? Вы не показываете связанный код. Вы используете вариант. В контейнере. Хорошо. Это в основном все, что мы знаем сейчас – sehe

+0

@sehe, Это основная проблема, что это какой-то внутренний посетитель. Когда я смотрю backtrace в gdb, я вижу, что ошибка появилась во время копирования вектора. – justanothercoder

ответ

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 
} 

Конечно, этот образец contrived², потому что я не знаю ваш фактический код/использование случай.

Последнее утверждение не выполняется. Это связанно с тем, что порядок операций, внутренне, таков, что первоначальный вариант очищается (и содержали значение разрушенного) перед тем нового значения присваивается:

«Никогда-Empty» Гарантия

Хотя никогда пусто гарантия может показаться на первый взгляд «очевидно», это на самом деле даже не просто, как реализовать это в общем

Cf. 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); 

Просто потому что нет в противном случае.


¹ всегда опасно!Даже Скотт Мейерс почувствовать это в его «Более эффективный C++», см erratum p.200/202

² связывал: What does the standard library guarantee about self move assignment?

+0

Отличное объяснение! Он заслуживает большего внимания. – Nawaz

+0

BTW, что такое 'std :: move (v.begin(), v.end(), v.begin());'? такой перегрузки нет. – Nawaz

+0

@ Наваз там нет? http://en.cppreference.com/w/cpp/algorithm/move – sehe

 Смежные вопросы

  • Нет связанных вопросов^_^