C++ 如何将Foo*迭代器转换为Foo向量?
如果我有一个包含std::list的类,并且该类具有公共方法begin和end来返回该列表的迭代器,那么我如何实现其他方法来将迭代器返回到std::list,最好不使用boost 我宁愿不维护指针的并行容器 编辑: 我有一个很大的代码库,我想改进。它有一个树状数据结构,其基类有一个返回对象子对象的方法:C++ 如何将Foo*迭代器转换为Foo向量?,c++,iterator,C++,Iterator,如果我有一个包含std::list的类,并且该类具有公共方法begin和end来返回该列表的迭代器,那么我如何实现其他方法来将迭代器返回到std::list,最好不使用boost 我宁愿不维护指针的并行容器 编辑: 我有一个很大的代码库,我想改进。它有一个树状数据结构,其基类有一个返回对象子对象的方法: class FooBase { // ... virtual bool getChildren(std::vector<FooBase *>& childre
class FooBase
{
// ...
virtual bool getChildren(std::vector<FooBase *>& children);
virtual size_t getChildrenCount() const { return 0; };
// ...
}
有一个实现子对象集合的模板类:
template <class T>
class FooCollection: public FooBase
{
public:
typedef typename std::list<T> ContainerType;
typedef typename ContainerType::iterator iterator;
typedef typename ContainerType::const_iterator const_iterator;
private:
ContainerType _items;
public:
// ...
const_iterator begin() const { return itemsM.begin(); };
const_iterator end() const { return itemsM.end(); };
iterator begin() { return itemsM.begin(); };
iterator end() { return itemsM.end(); };
virtual bool getChildren(std::vector<FooBase *>& children)
{
for (iterator it = itemsM.begin(); it != itemsM.end(); ++it)
children.push_back(&(*it));
return (itemsM.size() != 0);
};
// ...
};
代码使用不同的FooCollection类在已知类的位置提供的迭代器,以及在遍历树时使用FooBase::getChildren。我认为FooBase::getChildren可以用迭代器代替,但也许我错了?可以创建指向std::list中Foo元素的指针集合或容器,但这是不可靠的。问题是列表拥有它复制的Foo项,并且允许它在未经批准的情况下更改这些项的位置。因此,如果您有一个指向列表中第三个元素的指针,那么列表可以移动该元素,并且您的指针将在您不知情的情况下无效 更好的解决方案是动态分配Foo项并将智能指针存储在不同的列表中。这允许您按不同的键对项目进行排序。例如,您可以让list1按Foo中的第一个字段排序,另一个列表按Foo中的第三个字段排序
您必须提供自定义排序functor,因为默认操作是按智能指针的值排序,这是没有人真正想要的。可以创建指向std::list中Foo元素的指针集合或容器,但这是不可靠的。问题是列表拥有它复制的Foo项,并且允许它在未经批准的情况下更改这些项的位置。因此,如果您有一个指向列表中第三个元素的指针,那么列表可以移动该元素,并且您的指针将在您不知情的情况下无效 更好的解决方案是动态分配Foo项并将智能指针存储在不同的列表中。这允许您按不同的键对项目进行排序。例如,您可以让list1按Foo中的第一个字段排序,另一个列表按Foo中的第三个字段排序
您必须提供自定义排序functor,因为默认操作是按智能指针的值排序,这是没有人真正想要的。std::list::iterator的取消引用操作符重载返回对相应Foo对象的引用。因此,如果希望Foo对象的地址位于std::list::iterator object it,那么可以使用&*it,它的类型为Foo*
如果确实需要在指针上使用可递增的迭代器,那么可以编写一个迭代器类来存储std::list::iterator成员,比如说,在取消引用时返回&*它。请注意,这样的迭代器类只能满足常量迭代器概念,因为&*它是一个r值。std::list::iterator的解引用操作符重载返回对相应Foo对象的引用。因此,如果希望Foo对象的地址位于std::list::iterator object it,那么可以使用&*it,它的类型为Foo*
如果确实需要在指针上使用可递增的迭代器,那么可以编写一个迭代器类来存储std::list::iterator成员,比如说,在取消引用时返回&*它。请注意,这样的迭代器类只能满足常量迭代器概念,因为&*它是一个r值。此结构将有所帮助。它修改迭代器,使其解引用时返回指针而不是引用:
struct PointerInstead : public list<Foo>::iterator {
PointerInstead(const list<Foo>::iterator &x) : list<Foo>::iterator(x) { }
Foo * operator * () const {
Foo &f = *(*( (list<Foo>::iterator *) (this) ));
return &f;
}
};
以下是其使用示例:
for(PointerInstead i = l.begin(); i != l.end(); i++) {
cout << i->first << '\t' << i->second << endl;
printf("%p\n", (*i));
}
然后您可以编写一个pointerBegin方法,该方法返回类似于PointerSteadThis->begin的内容。此结构将有所帮助。它修改迭代器,使其解引用时返回指针而不是引用:
struct PointerInstead : public list<Foo>::iterator {
PointerInstead(const list<Foo>::iterator &x) : list<Foo>::iterator(x) { }
Foo * operator * () const {
Foo &f = *(*( (list<Foo>::iterator *) (this) ));
return &f;
}
};
以下是其使用示例:
for(PointerInstead i = l.begin(); i != l.end(); i++) {
cout << i->first << '\t' << i->second << endl;
printf("%p\n", (*i));
}
然后您可以编写一个pointerBegin方法,该方法返回类似于PointerSteadThis->begin的内容。编写一个简单的迭代器类并使用它怎么样
class myIterator : std::iterator<std::list<Foo>::iterator::iterator_category
, Foo*, std::list<Foo>::iterator::distance_type
, Foo**, Foo*&>
{
public:
myIterator(const std::list<Foo>::iterator& lIt) : it(lIt) {}
myIterator(const myIterator& myIt) : it(myIt.it) {}
myIterator& operator++() {++it;return *this;}
myIterator operator++(int)
{
myIterator copy(*this);
++it;
return copy;
}
myIterator& operator--() {--it;return *this;}
myIterator operator--(int)
{
myIterator copy(*this);
--it;
return copy;
}
bool operator==(const myIterator& rhs) {return it==rhs.it;}
bool operator!=(const myIterator& rhs) {return it!=rhs.it;}
Foo* operator*() {return &(*it);}
private:
std::list<Foo>::iterator it;
};
编写一个简单的迭代器类并使用它怎么样
class myIterator : std::iterator<std::list<Foo>::iterator::iterator_category
, Foo*, std::list<Foo>::iterator::distance_type
, Foo**, Foo*&>
{
public:
myIterator(const std::list<Foo>::iterator& lIt) : it(lIt) {}
myIterator(const myIterator& myIt) : it(myIt.it) {}
myIterator& operator++() {++it;return *this;}
myIterator operator++(int)
{
myIterator copy(*this);
++it;
return copy;
}
myIterator& operator--() {--it;return *this;}
myIterator operator--(int)
{
myIterator copy(*this);
--it;
return copy;
}
bool operator==(const myIterator& rhs) {return it==rhs.it;}
bool operator!=(const myIterator& rhs) {return it!=rhs.it;}
Foo* operator*() {return &(*it);}
private:
std::list<Foo>::iterator it;
};
它是std::list还是std::vector。你的头衔说明了一件事,问题说明了另一件事。@Evan:谢谢,我想该睡觉了。不过,容器的类型实际上并不重要,是否可以为同一个容器同时使用两种类型的迭代器?为什么需要std::list::iterator?难道你不能自己编写一个简单的迭代器来封装std::list::iterator,并在取消引用时给出某个Foo实例的地址吗?如果你试图解释你想要实现什么,而不是试图解释你认为
答案应该是。一方面,你说你想要一个std::list的迭代器,但另一方面,你说你不想要一个。。指针的容器,即std::list。所以我不明白你说的前者是什么意思。它是std::list还是std::vector。你的头衔说明了一件事,问题说明了另一件事。@Evan:谢谢,我想该睡觉了。不过,容器的类型实际上并不重要,是否可以为同一个容器同时使用两种类型的迭代器?为什么需要std::list::iterator?难道你不能自己编写一个简单的迭代器来封装std::list::iterator,并在取消引用时给出某个Foo实例的地址吗?如果你试图解释你试图实现的目标,而不是试图解释你认为解决方案应该是什么,这可能会更清楚,你说你想要一个std::list的迭代器,但另一方面,你说你不想要一个。。指针的容器,即std::list。所以我想我不明白你说的前者是什么意思。@Daniel Trebbien:我刚刚注意到你在几分钟内就以类似的答案击败了我。我还没有看到它。很好,但是从标准迭代器派生是不安全的。例如,++运算符可以实现为自由函数T&operator++std::list::iterator&而不是成员函数T&std::list::iterator::operator++。@Potatoswatter:这是否意味着自由函数的相同问题也适用于@Maciej Hehl的答案?有没有一种最简单的方法来创建一个在各个方面都像另一个类型的类型,包括在自由函数中,但只需稍加修改?转换操作符呢?转换运算符是否会使自由函数发挥作用?可能从list::iterator执行私有继承,并包含运算符list::iterator&converter?几分钟前我建议使用私有继承,但我不应该这样做。请不要理会,马塞伊的想法是对的。转换函数不会有帮助。他没有继承,而是使用一个包含基类和同一个运算符的表达式用一个函数重载每个运算符。您可以编写一个泛型类来实现每个操作符,并从中继承。我想那应该是一个标准设施…哦,好吧。另外,我忘了,指针是使用内置的非重载运算符的随机访问迭代器。@Daniel Trebbien:我刚刚注意到你在几分钟内就找到了类似的答案。我还没有看到它。很好,但是从标准迭代器派生是不安全的。例如,++运算符可以实现为自由函数T&operator++std::list::iterator&而不是成员函数T&std::list::iterator::operator++。@Potatoswatter:这是否意味着自由函数的相同问题也适用于@Maciej Hehl的答案?有没有一种最简单的方法来创建一个在各个方面都像另一个类型的类型,包括在自由函数中,但只需稍加修改?转换操作符呢?转换运算符是否会使自由函数发挥作用?可能从list::iterator执行私有继承,并包含运算符list::iterator&converter?几分钟前我建议使用私有继承,但我不应该这样做。请不要理会,马塞伊的想法是对的。转换函数不会有帮助。他没有继承,而是使用一个包含基类和同一个运算符的表达式用一个函数重载每个运算符。您可以编写一个泛型类来实现每个操作符,并从中继承。我想那应该是一个标准设施…哦,好吧。另外,我忘了,指针是使用内置的非重载运算符的随机访问迭代器。当然,除了在删除期间,列表在任何操作中都不允许移动其元素的内存位置。该标准要求迭代器和指向列表元素的引用或指针在任何操作中保持有效,但这并不意味着删除引用的元素。当然,除了在删除过程中,列表不允许在任何操作中移动其元素的内存位置。该标准要求迭代器和指向列表元素的引用或指针在任何不意味着删除引用元素的操作中保持有效。