智能指针的迭代和容器
Posted
技术标签:
【中文标题】智能指针的迭代和容器【英文标题】:Iterating & containers of smart pointers 【发布时间】:2010-02-12 23:45:16 【问题描述】:我有一个指向可变对象的智能指针容器。我必须编写两个 for_each 循环,一个用于将对象作为只读数据访问,另一个用于可变数据。编译器告诉我std::vector< boost::shared_ptr<Object> >
与std::vector< boost::shared_ptr<const Object> >
不同,请注意const
。
这是我的示例代码:
#include <vector>
#include "boost/shared_ptr.hpp"
#include <iterator>
class Field_Interface
; ;
typedef boost::shared_ptr<Field_Interface> Ptr_Field_Interface;
typedef boost::shared_ptr<const Field_Interface> Ptr_Const_Field_Interface;
struct Field_Iterator
: std::input_iterator<std::forward_iterator_tag, Ptr_Field_Interface>
// forward iterator methods & operators...
;
struct Const_Field_Iterator
: std::input_iterator<std::forward_iterator_tag, Ptr_Const_Field_Interface>
// forward iterator methods & operators...
;
struct Field_Functor
virtual void operator()(const Ptr_Field_Interface&) = 0;
virtual void operator()(const Ptr_Const_Field_Interface&) = 0;
;
class Record;
typedef boost::shared_ptr<Record> Ptr_Record;
typedef boost::shared_ptr<const Record> Ptr_Const_Record;
class Record_Base
protected:
virtual Field_Iterator beginning_field(void) = 0;
virtual Field_Iterator ending_field(void) = 0;
virtual Const_Field_Iterator const_beginning_field(void) = 0;
virtual Const_Field_Iterator const_ending_field(void) = 0;
void for_each(Field_Functor * p_functor)
Field_Iterator iter_begin(beginning_field());
Field_Iterator iter_end(ending_field());
for (; iter_begin != iter_end; ++ iter_begin)
(*p_functor)(*iter_begin);
;
class Record_Derived
public:
typedef std::vector<Ptr_Field_Interface> Field_Container;
typedef std::vector<Ptr_Record> Record_Container;
private:
Field_Container m_fields;
Record_Container m_subrecords;
;
鉴于以上所有细节,如何在Record_Derived
中实现Record_Base
的纯抽象方法?
我试过了:
返回m_fields.begin()
,
返回转换错误(不能
转换std::vector<...> to
Field_Iterator
)
返回&m_fields[0]
,即
危险的,因为它假设了一些东西
关于std::vector
的内部结构。
顺便说一句,我没有使用 std::for_each
,因为我必须遍历字段容器和子记录容器。
【问题讨论】:
我很好奇,你用什么编译器来编译样本? VC8 和 GCC3/4 不起作用。 @gf:我认为他可能正在使用 STLPort,它仍然具有std::forward_iterator
模板,用于向后兼容标准的早期草案。
@gf, @Emile:我的错,标识符应该是std::forward_iterator_tag
。我正在使用 MS Visual Studio 2008。给出的最喜欢的示例无法编译,因为它是用于显示概念的精简版本。
【参考方案1】:
您所做的与Composite 和Visitor 模式相似。这两种模式很好地融合在一起,所以您似乎走在了正确的轨道上。
要实现复合模式,请分配以下角色(请参阅复合模式 UML 图):
叶 ->Field
复合 -> Record
组件->Field
和Record
的抽象基类(想不出好名字)
在复合类型上调用的组件操作会以递归方式传递给所有子类型(叶子和其他嵌套的复合类型)。
要实现访问者模式,请在仿函数类中为每个组件子类型(字段和记录)重载 operator()
。
我建议您阅读“四人帮”的 Design Patterns 书籍,它更好地解释了这些概念,并且比我可能做的更详细。
这里有一些示例代码可以激发您的兴趣:
#include <iostream>
#include <vector>
#include "boost/shared_ptr.hpp"
#include "boost/foreach.hpp"
class Field;
class Record;
struct Visitor
virtual void operator()(Field& field) = 0;
virtual void operator()(Record& field) = 0;
;
class Component
public:
virtual bool isLeaf() const return true;
virtual void accept(Visitor& visitor) = 0;
;
typedef boost::shared_ptr<Component> ComponentPtr;
class Field : public Component
public:
explicit Field(int value) : value_(value)
void accept(Visitor& visitor) visitor(*this);
int value() const return value_;
private:
int value_;
;
class Record : public Component
public:
typedef std::vector<ComponentPtr> Children;
Record(int id) : id_(id)
int id() const return id_;
Children& children() return children_;
const Children& children() const return children_;
bool isLeaf() const return false;
void accept(Visitor& visitor)
visitor(*this);
BOOST_FOREACH(ComponentPtr& child, children_)
child->accept(visitor);
private:
int id_;
Children children_;
;
typedef boost::shared_ptr<Record> RecordPtr;
struct OStreamVisitor : public Visitor
OStreamVisitor(std::ostream& out) : out_(out)
void operator()(Field& field) out_ << "field(" << field.value() << ") ";
void operator()(Record& rec) out_ << "rec(" << rec.id() << ") ";
std::ostream& out_;
;
int main()
RecordPtr rec(new Record(2));
rec->children().push_back(ComponentPtr(new Field(201)));
rec->children().push_back(ComponentPtr(new Field(202)));
RecordPtr root(new Record(1));
root->children().push_back(ComponentPtr(new Field(101)));
root->children().push_back(rec);
OStreamVisitor visitor(std::cout);
root->accept(visitor);
在 Record 中,您可能希望提供用于操作/访问子级的方法,而不是返回对底层子级向量的引用。
【讨论】:
@Emile:谢谢,我对Visitor很熟悉,我会用复合模式来刷新我的记忆。我突然想到一个想法:将Record_Base
简化为容器,并转换为标准容器惯用语,以便std::for_each
可以在Record_Base
容器上工作。【参考方案2】:
我建议不要在使用通用容器类型时编写自己的迭代器。当您编写自己的容器时,编写自己的迭代器是有意义的。但是,当您计划编写自定义迭代器时,请查看 Boost.Iterator 包。
【讨论】:
【参考方案3】:如果你想对用户隐藏std::vector
及其迭代器,那么你需要提供多态迭代器来配合你的多态RecordBase
容器。从 Adobe ASL 库中查看 any_iterator
。 Theselinks 也可能有帮助。
但是,您应该考虑在设计中使用 Composite 和 Visitor 模式,而不是费尽心思。请参阅我的其他答案。
【讨论】:
以上是关于智能指针的迭代和容器的主要内容,如果未能解决你的问题,请参考以下文章