2010-03-01 106 views
6

我有一个类,产生任意数量的工人对象,计算他们的结果到std::vector。我将在某些点删除一些工作对象,但我想保留他们的结果,只按照spawned他们知道的那个类别。因此,我为类A中的输出提供了向量。我有(IMO)三个选项:我可以指向矢量,引用或迭代器作为成员。虽然迭代器选项有一定的退步(迭代器可以递增)。我不确定指针或引用是否更清晰。 我觉得引用更好,因为它们不能为NULL,并且要求存在一个向量。迭代器与参考与指针

我最不确定的是参考文献的有效性。 std::list< std::vector<int> >上的某些操作会使其失效吗?这些操作是否与使std::list的迭代器无效相同?有没有另外一种方法我现在没有看到?此外,与容器的耦合感觉不对:我强制将一个特定的容器加入到Cruncher类中。提供为清楚起见

代码:

#include <list> 
#include <vector> 
#include <boost/ptr_container/ptr_list.hpp> 

class Cruncher { 
    std::vector<int>* numPointer; 
    std::vector<int>& numRef; 
    std::list< std::vector<int> >::iterator numIterator; 
public: 
    Cruncher(std::vector<int>*); 
    Cruncher(std::vector<int>&); 
    Cruncher(std::list< std::vector<int> >::iterator); 
}; 

class A { 
    std::list< std::vector<int> > container; 
    boost::ptr_list< std::vector<int> > container2; 
    std::vector<Cruncher> cruncherList; 
}; 

回答

6
如果

迭代器被无效,它也将无效的指针/参考迭代器被转换成。如果你有这样的:

std::vector<T>::iterator it = ...; 
T *p = &(*it); 
T &r = *p; 

如果迭代器失效(例如调用的push_back可以无效所有现有的矢量迭代器),指针和引用也将失效。

从标准23.2.4.2/5(矢量容量):

注:重新分配无效的所有引用,指针和迭代器指的是序列中的元素。

对于std :: list,同样的一般原则也适用。如果迭代器失效,迭代器转换成的指针和引用也失效。

std :: list和std :: vector之间的区别是导致迭代器失效的原因。只要不删除它所指的元素,std :: list迭代器就是有效的。因此,如果std::vector<>::push_back可以使迭代器无效,则std::list<>::push_back不能。

+0

我打算使用std :: list来存储指向对象的指针样品。如果您只是将标准的报价更改为解释列表失效的部分,则您的答案没问题。 – pmr

+0

@pmr - 更新了我的答案,以包含更多关于列表的信息。 –

1

如果在产生工作线程后重新分配父代的向量内容,那么它们的指针,引用,迭代器或其他什么都是几乎肯定是无效。列表可能不同(给定它们如何分配),但我不知道,甚至可能取决于平台。

基本上,如果你有多个工作线程,那么在父类上实际上有一个方法可以将结果转储回来,只要这个副本不是那种赋税就可能是最安全的。当然,它不如直接分配给父母,但是你需要确保你倾倒的容器在重新分配时不会“丢失”。

如果您使用的列表保证不会在成员添加(或删除)时重新分配其“其他”空间,那么这将实现您正在寻找的内容,但该矢量绝对是不安全的。但无论哪种方式,只要您的“根容器”不会围绕其内容移动,您访问它的方式(指针,引用或迭代器)可能无关紧要。

编辑:

如在下面的评论中提到,这里是从SGI's website(重点煤矿)对列表中的块:

列出有 插入和拼接不 的重要财产使迭代器无效以列出元素, 并且即使删除也只会使指向已删除元素的 元素的迭代器仅失效 。的 排序的迭代器可以改变 (即目录::迭代器可能 的确要比之前 列表手术后不同的前置或后续 ),但迭代器本身 不会失效或制成 指向不同元素,除非 表示无效或突变为 显式。

因此,这基本上是说“使用一个列表作为您的主存储”,然后每个工人可以转储到自己的,并知道它不会失效时,另一个工人完成,他们的载体从名单。

+0

只要当前指向的元素未被擦除,列表迭代器仍然有效。 – James

+0

你说得对,自动填充。作者可以在关于列表的段落中参考http://stackoverflow.com/questions/1436020/c-stl-containers-whats-the-difference-between-deque-and-list/1436038#1436038。 – fogo

+0

@fogo:谢谢,我编辑了我的OP,添加了SGI网站上的文字。 –

0

在C++的当前版本(即无移动构造函数)中,指向嵌入在std :: list中的项的指针将与列表迭代器一起失效。

如果你使用了std :: list *>,那么vector *可以移动,但vector不会,所以你的指向vector的指针将保持有效。

随着C++ 0x中的移动构造函数的增加,矢量内容可能会保持放置状态,除非矢量本身被调整大小,但是任何这样的假设本质上都是不可移植的。

0

我喜欢指针参数。这是一个风格问题。我更喜欢这种参数类型风格:

  • 强制参考:大对象正在传递阅读。参考避免了浪费的复制。看起来就像在通话点传递值。
  • 指针:读取对象并编写。该电话将有一个“&”来获取指针,因此在代码审查期间写作变得明显。
  • 非常量引用:禁用,因为代码审查无法确定哪些参数可能会作为副作用发生更改。

正如你所说,迭代器在父容器类型上创建了一个无意义的依赖关系。 (std :: list被实现为一个双链表,所以只有删除它的入口才会使向量无效。所以它会起作用。)

+1

将非常量引用与指针进行比较时,副作用有何区别?除了在另一个地方提及另一个&符号之外,我没有看到任何其他的东西。 – pmr

+0

当函数被调用时,非const引用看起来完全像传递值,但允许函数更改参数。这意味着阅读代码的人必须阅读每个函数的所有文档,以正确地知道函数可能会发生什么变化。用我描述的风格,你可以阅读一个调用,并知道没有符号的参数不会被改变,而有可能的参数将被改变。这对于大型软件的正式代码评审可能有帮助。 –

+1

如果您还没有阅读函数的文档,则不应该调用它。编辑:你确定不应该审查它。 –