【问题标题】:iterators for vector of pointers指针向量的迭代器
【发布时间】:2011-04-15 02:43:26
【问题描述】:

我阅读了另一篇文章,该文章回答了有关指针向量迭代器的问题。我试图在我的代码中使用相同的概念,但我收到了一些编译错误。我的代码基于的代码示例是:

vector<c*> cvect;
cvect.push_back(new sc);
vector<c*>::iterator citer;
for(citer=cvect.begin(); citer != cvect.end(); citer++) {
    (*citer)->func();
}

我想使用类似的概念为具有两个数据成员的类创建一个深拷贝构造函数,这些数据成员是指向对象的指针向量。我的代码是这样的:

class MyContainer {
    vector<MyStuff*> vecOne;
    vector<MyStuff*> vecTwo;

 public:
    MyContainer(const MyContainer& other);
};

MyContainer::MyContainer(const MyContainer& other) {
    // copy vector one
    vector<MyStuff*>::iterator vec1_itr;
    for (vec1_itr = other.vecOne.begin(); vec1_itr != other.vecOne.end(); vec1_itr++) {
        vecOne.push_back(new MyStuff(vec1_itr));
    }

    // copy vector two
    vector<MyStuff*>::iterator vec2_itr;
    for (vec2_itr = other.vecTwo.begin(); vec2_itr != other.vecTwo.end(); vec2_itr++) {
        vecTwo.push_back(new MyStuff(vec2_itr));
    }
}

我收到一些编译错误,例如:

/path/MyContainer.cpp:38: 错误:'vec1_Itr = other-&gt;MyContainer::vecOne. std::vector&lt;_Tp, _Alloc&gt;::begin [with _Tp = MyStuff*, _Alloc = std::allocator&lt;MyStuff*&gt;]()'中的'operator='不匹配

候选人是:__gnu_cxx::__normal_iterator&lt;MyStuff*, std::vector&lt;MyStuff, std::allocator&lt;MyStuff&gt; &gt; &gt;&amp; __gnu_cxx::__normal_iterator&lt;MyStuff*, std::vector&lt;MyStuff, std::allocator&lt;MyStuff&gt; &gt; &gt;::operator=(const __gnu_cxx::__normal_iterator&lt;MyStuff*, std::vector&lt;MyStuff, std::allocator&lt;MyStuff&gt; &gt; &gt;&amp;)

我也收到operator!= 的错误...而另一个向量的另一组相同的错误。

【问题讨论】:

  • 您如何在class MyContainer 中声明vecOnevecTwo
  • 在旁注中,尝试使用MyStuff 复制构造函数,而不是向其传递迭代器。您可以将其称为...(new MyStuff(**vec1_itr)。这样会更简单
  • 当心向量是否可以包含指向从c派生的类型的对象的指针,这是合法的,因为您将切片它们。

标签: c++ pointers vector iterator


【解决方案1】:

您忘记取消引用迭代器。试试这个:

vecOne.push_back(new MyStuff( **vec1_itr ));

编辑 0:

是的,应该是双重取消引用(上面已修复)。它应该是const_terator,因为您正在处理包含对象的const

vector<MyStuff*>::const_iterator vec1_itr;

【讨论】:

  • 错误告诉他他违反了const。跟他类的构造函数无关。
  • 调用MyStuff拷贝构造函数,调用方式为:MyStuff(**vec1_itr)
  • 感谢 cmets @wilhelmtell、@Nikolai 和 @iammilind。更改为 const_iterator 并正确取消引用我的 .push_back(new MyStuff(**vecX_itr)); 中的迭代器解决了我的问题。
  • 我在可视化我的const_iterator 的这些双重取消引用时遇到了麻烦,即使它们似乎运行正常。 ptrs 到MyStuff 对象的第一个向量是主列表。在指向MyStuff 对象的第二个ptrs 向量中,所有ptrs 都指向第一个向量指向的MyStuff 对象的子集。我担心我有不相关的向量,其中第二个向量指向独立于第一个向量的元素。 other 对象的向量元素是从文件中读取的。复制构造函数应该只读取文件吗? other 持有对文件名的引用。
【解决方案2】:

不要将参数作为const 或将vec1_itr 声明为const_iterator。这里的问题是vecOne.begin() 返回一个const_iterator,因为容器是const。如果要更改容器,则必须删除 const 限定符。

附带说明,如果持有一个指针容器意味着您需要管理容器中的指针并且您有两个这样的容器,那么您应该将容器移动到它自己的类中。尽量避免在一个类中管理多个资源。

【讨论】:

  • 我不确定我是否完全理解您的第二条评论。我有两个正在使用的课程。从第一个类实例化的对象包含几条数据。第二类对象包含一些简单的数据以及两个指向第一类对象的指针向量。我这样做是为了尽量减少复制从第一类派生的对象的需要。第一个向量就像一个主列表,第二个向量是主列表的子集。那有意义吗?感谢您在const_iterator 上的cmets。这很有意义。
  • 完美。 const_Iterator 解决了两个错误,如上所述,将.push_back 代码调整为vecOne.push_back(new MyStuff(**vec1_itr)); 解决了其他错误。
【解决方案3】:

!!内存泄漏警报!!

您的代码是泄漏的。

复制构造函数 (std::bad_alloc?) 中抛出的任何异常都将导致内存泄漏,因为传递给 vector 的内存将永远不会被清理(不会调用析构函数,因为对象从未首先构建)。

当然,您可以添加所需的 try/catch,但我警告您,代码很快就会变得笨拙(您需要几个)。

这是违反资源管理规则1的直接结果:

一个对象应该管理最多一个资源,在这种情况下它不应该做任何其他事情。

这意味着如果您的对象是一个业务对象(内部包含应用程序逻辑),那么它不应该直接处理资源管理,而是使用已经存在的管理器。

在您的情况下,您有两种解决方案:

  1. 推荐:由于这里没有使用多态,所以不要使用指针。 std::vector&lt;MyStuff&gt; 很好
  2. 如果您需要多态性,但没有包含在这个玩具示例中,请使用boost::ptr_vector&lt;MyStuff&gt;

加分项:他们两个定义了合理的拷贝构造函数、赋值操作符和析构函数,这样你就不用自己重写了。

编辑:

正如@David 所说,如果您需要多态,则不能使用复制构造,因此需要:

  • clone 方法或等效方法
  • 指针和动态内存分配

boost::ptr_vector 提供您所需的一切(复制时自动使用clone 方法)。

【讨论】:

  • +1,为了提问者的缘故:注意,如果您需要多态性,其他解决方案将无法使用,复制构造将 slice i> 包含的对象。
  • 我感谢所有这些额外的 cmets。就我而言,这个项目实际上是一个基本内存分配/管理、向量使用和一些文件 I/O 混合的练习。出于我的目的,可以安全地假设构造函数永远不会失败。我知道这在专业代码中是不可接受的。
猜你喜欢
  • 1970-01-01
  • 2014-10-13
  • 2014-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-18
相关资源
最近更新 更多