Перебор const T& в std::vector‹std::unique_ptr‹T› ›

У меня есть такой класс:

class RPNExpr
{
    std::vector<std::unique_ptr<Expr> > m_exprs;
};

Каждый элемент m_exprs выделяется функцией-построителем в куче, должен быть доступен для чтения другими классами, но полностью принадлежит RPNExpr и должен быть уничтожен, когда RPNExpr выходит за пределы области видимости.

Было бы неплохо, если бы читатели m_exprs могли получить итератор вместо const Expr&, то есть итератор, который скрывает тот факт, что вектор содержит unique_ptrs. Я хотел бы этого для согласованности с другими классами, которые хранят unique_ptrs в своих данных и возвращают им const T&.

Интерфейс для этого может выглядеть примерно так:

class RPNExpr
{
public:
    SomeIterator expr_begin();
    SomeIterator expr_end();
private:
    std::vector<std::unique_ptr<Expr> > m_exprs;
};

Затем потребители должны иметь возможность перебирать Exprs, используя стандартные операторы итератора.

Есть ли хороший способ сделать это? Должен ли я писать векторную оболочку, которая абстрагируется от указателей? Должен ли я вообще не делать этого и использовать что-то другое, кроме unique_ptrs в моем векторе?


person TartanLlama    schedule 04.09.2014    source источник
comment
Является ли boost::ptr_vector подходящей заменой?   -  person Siyuan Ren    schedule 04.09.2014
comment
@К.Р. Думаю, я мог бы использовать ptr_vector и вручную удалить все выражения в ~RPNExpr. Я надеялся, что смогу избежать использования boost и сохранить автоматическое удаление, но это кажется хорошей альтернативой, если это невозможно, спасибо.   -  person TartanLlama    schedule 04.09.2014
comment
Я думаю, что вы могли бы определить свой собственный класс итератора, который наследуется от итератора по умолчанию и возвращает const T& всякий раз, когда вы его разыменовываете.   -  person vratojr    schedule 04.09.2014
comment
@vratojr это возможно, но я думал, что наследование от vector‹T›::iterator было плохой практикой, поскольку они определяются реализацией?   -  person TartanLlama    schedule 04.09.2014
comment
@TartanLlama: boost::ptr_vector принимает на себя владение всеми указателями на элементы, поэтому вам не нужно и не следует удалять их в ~RPNExpr. И почему вы надеетесь избежать буста?   -  person Siyuan Ren    schedule 04.09.2014
comment
@TartanLlama: я думаю, что vratojr имел в виду наследовать от std::iterator, а не vector<T>::iterator   -  person Paul    schedule 04.09.2014
comment
@К.Р. Ах, я не заметил этого из моего беглого взгляда на документы. Я надеялся избежать форсирования, так как это проект, который я задумал, чтобы лучше понять C++11 и LLVM, поэтому небольшое переосмысление колеса не проблема; Я не против буста в принципе.   -  person TartanLlama    schedule 04.09.2014
comment
@TartanLlama: Пол прав, я имел в виду std::iterator или, лучше, правильный производный класс, который соответствует вашим потребностям.   -  person vratojr    schedule 05.09.2014


Ответы (1)


В boost есть адаптер итератора, который делает именно это:

#include <boost/iterator/indirect_iterator.hpp>
...
using ExprIterator = boost::indirect_iterator<std::vector<std::unique_ptr<Expr>>::iterator>;
ExprIterator expr_begin() { return std::begin(m_exprs); }
ExprIterator expr_end() { return std::end(m_exprs; }

Источник: http://www.boost.org/doc/libs/1_56_0/libs/iterator/doc/indirect_iterator.html

person slajoie    schedule 04.09.2014
comment
Спасибо, это работает хорошо. Вы даже можете создать шаблон этого using typedef, чтобы иметь общий итератор vector<unique_ptr<T>>->T&. - person TartanLlama; 05.09.2014