boost::multi_index_container:检索结束迭代器时出现问题

boost::multi_index_container: issue in retrieving end iterator

我有一个颜色 class。

我想创建一个 boost::multi_index_container,它使用颜色 ID 和颜色位置(在渐变内 class)作为键。

为了保持代码更具可读性,我在 IndexedColorSet class.

中封装了 boost 实现

我想检索按位置排序的颜色。为此,我创建了一个 getStartEndPositionIterators 方法,该方法 returns 开始和结束按位置排序的 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;
}

问题是 getStartEndPositionIterators return 一对或 引用 迭代器,当你想 return 迭代器本身(引用引用 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;
}

库作者已经向您展示了主要问题。这是我很高兴与您一起完成的实时编码清理:)

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