Iterator versus reference or pointer

I have a class that spawns an arbitrary number of work objects that compute their results in std::vector . I am going to delete some work objects at certain points, but I would like to save their results in a specific order, only known to the class that spawned them. Thus, I provide vectors for output in class A.

I have (IMO) three options: I can have pointers to vectors, links, or iterators as members. Although the iterator parameter has certain backlinks (the iterator can be increased.) I'm not sure if pointers or links are clearer. I feel that links are better because they cannot be NULL, and the cruncher will require a vector.

What I'm most unsure about is the correctness of the links. Won't they be canceled by some operations on std::list< std::vector<int> > ? Are these operations the same as invalidating std::list iterators? Is there any other approach that I do not see now? Also, the connection to the container does not seem to be correct: I force a specific container to the Cruncher class.

Code for clarity:

 #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
c ++ design
source share
4 answers

If the iterator is invalid, this will also invalidate the pointer / link into which the iterator was converted. If you have this:

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

if the iterator is invalid (for example, a push_back call can invalidate all existing vector iterators), the pointer and link will also be invalidated.

From standard 23.2.4.2/5 (vector capacity):

Notes. Redistribution invalidates all references, pointers, and iterators that reference elements in a sequence.

The same general principle holds for std :: list. If the iterator is invalid, the pointers and references that the iterator converts are also invalid.

The difference between std :: list and std :: vector causes the iterator to be invalid. The std :: list iserator is valid until you delete the element it refers to. Therefore, when std::vector<>::push_back can invalidate an iterator, std::list<>::push_back cannot.

+6
source share

If the contents of the parent vector are redistributed after spawning workflows, then their pointers, links, iterators, or something is almost certainly invalid. The list MAY be different (given how they are allocated), but I donโ€™t know and can even be platform dependent.

Basically, if you have multiple workflows, it is probably safe to actually have a parent class method to flush the results back until the copy is tax deductible. Of course, this is not as good as distributing directly in the parent, but then you need to make sure that the container you are throwing into does not get "lost" when redistributing.

If the list that you use is guaranteed not to redistribute its โ€œotherโ€ space when members are added (or deleted), then this will achieve what you are looking for, but the vector is definitely unsafe. But in any case, the way to access it (pointer, link, or iterator) probably does not matter, since your "root container" is not going to move its contents.

Edit:

As mentioned in the comments below, here is a block about the list from the SGI website (highlighted by me):

Lists have an important property that insertion and splicing do not invalidate iterators to enumerate elements, and that even deleting is invalid only iterators pointing to elements that are deleted. the order of iterators can be changed (that is, the list :: iterator may have a different predecessor or successor after the operation of the list than it was before), but the iterators themselves will not be invalidated or point to different elements if the invalidation or mutation is just Explicit.

So, this basically says โ€œuse the list as your master storeโ€, and then each worker can fall into place and knows that he will not be invalidated when the other worker is completely completed and their vector is removed from the list.

+1
source share

In the current version of C ++ (i.e. there are no move constructors) pointers to elements embedded in std :: list will be invalid along with list iterators.

If, however, you used std :: list *>, then the vector * could move, but the vector will not, so your pointer to the vector will remain valid.

With the addition of move constructors in C ++ 0x, vector content is likely to remain included unless the vector itself is modified, but any such assumption would be inherently not portable.

0
source share

I like the pointer parameter. This is a matter of style. I prefer the style of this type of parameter:

  • Link to a constant: a large object is passed for reading. Link avoids wasteful copying. It looks the same as passing by value at the dial peer.
  • Pointer: an object is passed for reading and writing. The call will have "&". to get a pointer, so the entry becomes apparent when viewing the code.
  • Non-constant link: Forbidden because code verification cannot determine which parameters can be changed as a side effect.

As you say, an iterator creates a meaningless dependency on the parent type of the container. (std :: list is implemented as a double-linked list, so only deleting its entry invalidates the vector. This will work.)

0
source share

All Articles