2015-11-09 5 views
1

У меня есть класс Color.boost :: multi_index_container: проблема с получением конечного итератора

Я хочу создать boost::multi_index_container, который использует идентификаторы цвета и цвет (он находится внутри класса градиента) в качестве ключей.

Чтобы сохранить код более читабельным, я инкапсулировал реализацию boost в классе IndexedColorSet.

Я хочу получить цвета, упорядоченные по их положению. Для этого я создал метод getStartEndPositionIterators, который возвращает начальный и конечный итератор контейнера multi_index_container, упорядоченного по положению.

Моя проблема заключается в том, что конечный итератор, похоже, работает неправильно. Если я создаю цикл, который печатает позицию всех итераторов от начала до конца, они печатаются правильно, но когда я дойду до конечного итератора, он бесконечно циклически перемещается между последним сохраненным значением и недопустимым значением.

Как я могу получить правый итератор конца? Что я делаю неправильно?

Использование boost 1.58.0 и gcc 5.2.1.

#include <boost/multi_index_container.hpp> 
#include <boost/multi_index/ordered_index.hpp> 
#include <boost/multi_index/identity.hpp> 
#include <boost/multi_index/member.hpp> 
#include <utility> 
#include <iostream> 

////////////////////////////////////////////////////////////// 
/// Class that must be inserted into multi_index_container. // 
////////////////////////////////////////////////////////////// 

class Color { 
public: 
    double red; 
    double green; 
    double blue; 
    double alpha; 
}; 

////////////////////////////////////////////////////// 
/// Class that implements the multi_index_container // 
/// using ordering by id and by position.   // 
////////////////////////////////////////////////////// 

class IndexedColorSet { 
public: 

    // Class that wil be used as multi_index_container template parameter. 
    class IndexedColor { 
    public: 
     int id; 
     double position; 
     Color color; 
     IndexedColor() {} 
     IndexedColor(int id, double position, const Color &color) : 
      id(id), position(position), color(color) {} 
    }; 

    // typedef for multi_index_container iterator 
    typedef ::boost::multi_index::detail::bidir_node_iterator<boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::index_node_base<IndexedColor, std::allocator<IndexedColor> > > > PositionIterator; 

public: 

    void insertColor(int id, double position, const Color &color); 
    // Retrieve begin and end iterator using position as index 
    std::pair<const PositionIterator&, const PositionIterator&> getStartEndPositionIterators() const; 

private: 

    // Tags 
    struct id{}; 
    struct position{}; 

    // Container creation. 
    // It creates an ordered_unique index using id 
    // and a ordered_not_unique index using position 
    typedef ::boost::multi_index_container< 
     IndexedColor, 
     ::boost::multi_index::indexed_by< 
      ::boost::multi_index::ordered_unique< 
       ::boost::multi_index::tag<id>, 
       BOOST_MULTI_INDEX_MEMBER(IndexedColor,int,id) 
      >, 
      ::boost::multi_index::ordered_non_unique< 
       ::boost::multi_index::tag<position>, 
       BOOST_MULTI_INDEX_MEMBER(IndexedColor,double,position) 
      > 
     > 
    > PrivateIndexedColorSet; 

private: 

    PrivateIndexedColorSet m_set; 
}; 

// Insert a color associated to id and position. 
void IndexedColorSet::insertColor(int id, double position, const Color &color) { 
    m_set.insert(IndexedColor(id, position, color)); 
} 

// Retrieve a std::pair containing begin and end iterator if multi_index_container 
// using the position as key. 
std::pair<const IndexedColorSet::PositionIterator&, const IndexedColorSet::PositionIterator&> IndexedColorSet::getStartEndPositionIterators() const { 
    const auto& positionSet = ::boost::multi_index::get<position>(m_set); 
    const auto& beginIt = positionSet.begin(); 
    const auto& endIt = positionSet.end(); 
    return std::pair<const PositionIterator&, const PositionIterator&>(beginIt, endIt); 
} 

int main() 
{ 
    IndexedColorSet set; 

    // Populate the set 
    int id1 = 1; 
    int id2 = 2; 
    int id3 = 3; 
    double position1 = 0.4; 
    double position2 = 0.6; 
    double position3 = 0.3; 
    Color color1{0.1, 0.3, 0.4, 0.5}; 
    Color color2{0.2, 0.4, 0.5, 0.6}; 
    Color color3{0.3, 0.4, 0.5, 0.6}; 
    set.insertColor(id1, position1, color1); 
    set.insertColor(id2, position2, color2); 
    set.insertColor(id3, position3, color3); 

    // Retrieve ordered position iterators 
    auto iterators = set.getStartEndPositionIterators(); 

    // Testing that are ordered 
    // I should obtain 
    // 0.3 
    // 0.4 
    // 0.6 
    // 
    // Instead I obtain 
    // 0.3 
    // 0.4 
    // 0.6 
    // 0 
    // 0.6 
    // 0 
    // 0.6 
    // 0 
    // 0.6 
    // 0... and so on 
    for (auto it = iterators.first; it != iterators.second; ++it) { 
     std::cout << it->position << std::endl; 
    } 
    return 0; 
} 
+0

из коробки, вы могли бы быть заинтересованы в библиотеках контейнеров: [live demo] (http://coliru.stacked-crooked.com/a/cc9475e14b7db2d1) – sehe

ответ

1

библиотека автор уже показал вам главную проблему. Вот живой кодировкой очистки, что я имел радость переходя с вами :)

Live On Coliru

#include <boost/multi_index_container.hpp> 
#include <boost/multi_index/ordered_index.hpp> 
#include <boost/multi_index/member.hpp> 
#include <boost/range/iterator_range.hpp> 
#include <iostream> 

struct Color { 
    double red; 
    double green; 
    double blue; 
    double alpha; 
}; 

namespace bmi = boost::multi_index; 

class IndexedColorSet { 
    public: 

    struct IndexedColor { 
     int id; 
     double position; 
     Color color; 
    }; 
    private: 

    typedef bmi::multi_index_container< 
     IndexedColor, 
     bmi::indexed_by< 
      bmi::ordered_unique<  bmi::tag<struct by_id>,  bmi::member<IndexedColor, int, &IndexedColor::id>  >, 
      bmi::ordered_non_unique< bmi::tag<struct by_position>, bmi::member<IndexedColor, double, &IndexedColor::position> > 
     > 
    > PrivateIndexedColorSet; 

    public: 
    // typedef for multi_index_container iterator 
    using PositionIterator = PrivateIndexedColorSet::index<by_position>::type::const_iterator; 
    using PositionRange = boost::iterator_range<PositionIterator>; 

    void insertColor(int id, double position, const Color &color); 
    PositionRange getPositionRange() const; 

    private: 
    PrivateIndexedColorSet m_set; 
}; 

// Insert a value 
void IndexedColorSet::insertColor(int id, double position, const Color &color) { 
    m_set.insert({id, position, color}); 
} 

// Retrieve the full range by_position 
IndexedColorSet::PositionRange IndexedColorSet::getPositionRange() const { 
    auto& positionSet = bmi::get<by_position>(m_set); 
    auto beginIt  = positionSet.begin(); 
    auto endIt  = positionSet.end(); 

    return { beginIt, endIt }; 
} 

int main() { 
    IndexedColorSet set; 

    // Populate the set 
    set.insertColor(1, 0.4, {0.1, 0.3, 0.4, 0.5}); 
    set.insertColor(2, 0.6, {0.2, 0.4, 0.5, 0.6}); 
    set.insertColor(3, 0.3, {0.3, 0.4, 0.5, 0.6}); 

    // Retrieve ordered position iterators 
    auto iterators = set.getPositionRange(); 

    for (auto& ic : iterators) { 
     std::cout << ic.position << std::endl; 
    } 
} 

Печатает

0.3 
0.4 
0.6 
+0

См. [Записанный прямой эфир] (https://www.livecoding.tv/video/review-mulitindex-container-application/), если вы хотите еще раз поймать мой первоначальный ответ :) – sehe

+0

Спасибо большое .. Я в порядке загипнотизированный вашим кодированием ... – Jepessen

2

Проблема заключается в том, что getStartEndPositionIterators возвращает пару или ссылки для итераторов, когда вы хотите вернуть Итераторов сами (ссылки относятся к объектам внутри getStartEndPositionIterators, которые становятся недействительными, как только функции члена выходов):

std::pair<PositionIterator,PositionIterator> getStartEndPositionIterators() const; 

Я очищены ваш код немного: в частности, то, как вы получаете тип PositionIterator абсолютно не документированы, вы можете сделать это законным путем, как показано ниже.

Live On Coliru

#include <boost/multi_index_container.hpp> 
#include <boost/multi_index/ordered_index.hpp> 
#include <boost/multi_index/identity.hpp> 
#include <boost/multi_index/member.hpp> 
#include <utility> 
#include <iostream> 

////////////////////////////////////////////////////////////// 
/// Class that must be inserted into multi_index_container. // 
////////////////////////////////////////////////////////////// 

class Color { 
public: 
    double red; 
    double green; 
    double blue; 
    double alpha; 
}; 

////////////////////////////////////////////////////// 
/// Class that implements the multi_index_container // 
/// using ordering by id and by position.   // 
////////////////////////////////////////////////////// 

class IndexedColorSet { 
public: 

    // Class that wil be used as multi_index_container template parameter. 
    class IndexedColor { 
    public: 
     int id; 
     double position; 
     Color color; 
     IndexedColor() {} 
     IndexedColor(int id, double position, const Color &color) : 
      id(id), position(position), color(color) {} 
    }; 

private: 

    // Tags 
    struct id{}; 
    struct position{}; 

    // Container creation. 
    // It creates an ordered_unique index using id 
    // and a ordered_not_unique index using position 
    typedef ::boost::multi_index_container< 
     IndexedColor, 
     ::boost::multi_index::indexed_by< 
      ::boost::multi_index::ordered_unique< 
       ::boost::multi_index::tag<id>, 
       BOOST_MULTI_INDEX_MEMBER(IndexedColor,int,id) 
      >, 
      ::boost::multi_index::ordered_non_unique< 
       ::boost::multi_index::tag<position>, 
       BOOST_MULTI_INDEX_MEMBER(IndexedColor,double,position) 
      > 
     > 
    > PrivateIndexedColorSet; 

public: 

    void insertColor(int id, double position, const Color &color); 
    // Retrieve begin and end iterator using position as index 
    typedef PrivateIndexedColorSet::index<position>::type::iterator PositionIterator; 
    std::pair<PositionIterator,PositionIterator> getStartEndPositionIterators() const; 

private: 

    PrivateIndexedColorSet m_set; 
}; 

// Insert a color associated to id and position. 
void IndexedColorSet::insertColor(int id, double position, const Color &color) { 
    m_set.insert(IndexedColor(id, position, color)); 
} 

// Retrieve a std::pair containing begin and end iterator if multi_index_container 
// using the position as key. 
std::pair< 
    IndexedColorSet::PositionIterator, 
    IndexedColorSet::PositionIterator> 
IndexedColorSet::getStartEndPositionIterators() const { 
    return std::make_pair(
     m_set.get<position>().begin(), 
     m_set.get<position>().end()); 
} 

int main() 
{ 
    IndexedColorSet set; 

    // Populate the set 
    int id1 = 1; 
    int id2 = 2; 
    int id3 = 3; 
    double position1 = 0.4; 
    double position2 = 0.6; 
    double position3 = 0.3; 
    Color color1{0.1, 0.3, 0.4, 0.5}; 
    Color color2{0.2, 0.4, 0.5, 0.6}; 
    Color color3{0.3, 0.4, 0.5, 0.6}; 
    set.insertColor(id1, position1, color1); 
    set.insertColor(id2, position2, color2); 
    set.insertColor(id3, position3, color3); 

    // Retrieve ordered position iterators 
    auto iterators = set.getStartEndPositionIterators(); 

    // Testing that are ordered 
    // I should obtain 
    // 0.3 
    // 0.4 
    // 0.6 
    for (auto it = iterators.first; it != iterators.second; ++it) { 
     std::cout << it->position << std::endl; 
    } 
    return 0; 
} 
+0

+1 Я потратил еще немного времени на очистку/просмотр, но вы прибили его, obvio usly – sehe

+0

Спасибо Это очень помогло мне. – Jepessen

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