【问题标题】:Does ptr_vector iterator not require increments?ptr_vector 迭代器不需要增量吗?
【发布时间】:2010-10-23 09:25:43
【问题描述】:
#include <boost/ptr_container/ptr_vector.hpp>
#include <iostream>
using namespace std;

class Derived
{
public:
        int i;
        Derived() {cout<<"Constructed Derived"<<endl;}
        Derived(int ii):i(ii) {cout<<"Constructed Derived"<<i<<endl;}
        ~Derived() {cout<<"* Destructed Derived"<<i<<endl;}
};

int main()
{
   boost::ptr_vector<Derived> pv;
   for(int i=0;i<10;++i) pv.push_back(new Derived(i));

   boost::ptr_vector<Derived>::iterator it;
   for (it=pv.begin(); it<pv.end();/*no iterator increment*/ )
        pv.erase(it);
   cout<<"Done erasing..."<<endl;
}

请注意,第二个 for 循环不会增加迭代器,但它会迭代并删除所有元素。我的问题是:

  1. 我的迭代技术和使用迭代器是否正确?
  2. 如果 for 循环中不需要迭代器增量,那么增量发生在哪里?
  3. 是使用迭代器更好还是普通整数就足够了(即:使用迭代器是否有任何附加值)? (因为我也可以擦除第 5 个元素,例如 pv.erase(pv.begin()+5);)
  4. 有什么方法可以直接将新对象分配到 ptr_vector 的特定位置(比如说第 5 个位置)?我正在寻找类似 pv[5]=new Derived(5); 的东西。有什么办法吗?

【问题讨论】:

    标签: c++ boost ptr-vector


    【解决方案1】:

    ptr_vector::iterator 就像普通的随机访问迭代器一样递增。在您的示例中,您可以在不实际增加的情况下擦除每个元素,因为在擦除一个元素之后,它之后的每个元素都会在数组中移动。因此,当您删除第 0 个元素时,您的迭代器现在指向 使用 为第 1 个元素但现在是第 0 个元素的元素,依此类推。换句话说,当整个向量向左移动时,迭代器保持原位。

    这与 ptr_vector 无关。请注意,普通的std::vector 也会发生相同的行为。

    还要注意,在删除它指向的元素后使用迭代器是危险的。在您的情况下,它可以工作,但最好采用 ptr_vector::erase 的返回值,这样您就可以得到一个保证有效的新迭代器。

     for (it = pv.begin(); it != pv.end(); )
            it = pv.erase(it);
    

    至于你的其他问题:

    如果您只想擦除特定元素,那么您当然应该使用pv.erase(pv.begin() + N) 直接擦除它。要将新值分配给指针向量中的特定元素,只需说 pv[N] = Derived(whatever)。重新分配值时不需要使用new。指针向量将在您分配新值的索引处调用对象的赋值运算符。

    【讨论】:

    • 太酷了!也希望能回答问题 3 和 4 :)
    • 不。我试过 pv[0]=Derived(888);并得到这个输出: Constructed Derived888 boostPtrVsSTL: /usr/include/boost/ptr_container/ptr_sequence_adapter.hpp:325: typename boost::ptr_container_detail::reversible_ptr_container<:ptr_container_detail::sequence_config voidptrseq>, CloneAllocator>::参考 boost::ptr_sequence_adapter::operator[](typename boost::ptr_container_detail::reversible_ptr_container<:ptr_container_detail::sequence_config voidptrseq>
    • [继续...],CloneAllocator>::size_type) [with T = Derived, VoidPtrSeq = std::vector >, CloneAllocator = boost ::heap_clone_allocator]:断言 `n size()' 失败。中止(核心转储)
    • @Nav:你在清理完容器后没有尝试做4)?断言表明索引 (0) 超出范围。
    • @Nav,您只能将元素分配给有效索引。如果您擦除向量中的所有内容,pv[0] 将不再是有效索引。如果向量为空,则需要使用push_back 添加新元素。
    【解决方案2】:

    我的迭代技术和使用迭代器是否正确?

    不,从容器中擦除通常会使指向被擦除项目的迭代器无效。如果可行,这只是实现细节的副作用。

    正确的方法是使用擦除方法的返回值:

     it = pv.erase(it);
    

    但是,对于清空容器,可以使用 clear 成员函数。

    如果在 for 循环中不需要迭代器增量,那么在哪里 增量发生了吗?

    这不会发生,因为您将始终擦除容器中的第一个项目(碰巧,可能不适用于其他容器)。

    使用迭代器更好还是普通整数就足够了(即: 使用是否有任何增值作用 迭代器)? (因为我也可以擦除 第5个元素 pv.erase(pv.begin()+5);)

    在随机访问容器中你可以这样做,否则不能(例如列表)。

    有没有办法将新对象分配到特定位置(让我们 说 ptr_vector 的第 5 个位置), 直接地?我在找东西 喜欢pv[5]=new Derived(5);。反正 这样做?

    根据升压参考:

    pv.replace(5, new Derived(5));
    

    这将返回智能指针中的现有指针,因此它将被自动释放。 (奇怪的是,这需要一个索引,而不是一个迭代器......)。

    或者:

    pv[5] = Derived(5);
    

    但这只会修改存储的对象,不会改变指针。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-24
      相关资源
      最近更新 更多