Been a while since I've used C++. Can I do something like this?:
for (vector<Node>::iterator n = active.begin(); n!=active.end(); ++n) {
n->ax /= n->m;
}
where Node is an object with a few floats in it?
If written in Java, what I'm trying to accomplish is something similar to:
for (Node n : this.active) {
n.ax /= n.m;
}
where active is an arrayList of Node objects.
I think I am forgetting some quirk about passing by reference or something throws hands in the air in desperation
Yes. This syntax basically works for almost all STL containers.
// this will walk it the container from the beginning to the end.
for(container::iterator it = object.begin(); it != object.end(); it++)
{
}
object.begin() - basically gives an iterator the first element of the container.
object.end() - the iterator is set to this value once it has gone through all elements. Note that to check the end we used !=.
operator ++ - Move the iterator to the next element.
Based on the type of container you may have other ways to navigate the iterator (say backwards, randomly to a spot in the container, etc). A good introduction to iterators is here.
Short answer: yes, you can.
The iterator is a proxy for the container element. In some cases the iterator is literally just a pointer to the element.
Your code works fine for me
#include <vector>
using std::vector;
struct Node{
double ax;
double m;
};
int main()
{
vector<Node> active;
for (vector<Node>::iterator n = active.begin(); n!=active.end(); ++n) {
n->ax /= n->m;
}
}
You can safely change an object contained in a container without invalidating iterators (with the associative containers, this applies only to the 'value' part of the element, not the 'key' part).
However, what you might be thinking of is that if you change the container (say by deleting or moving the element), then existing iterators might be invalidated, depending on the container, the operation being performed, and the details of the iterators involved (which is why you aren't allowed to change the 'key' of an object in an associative container - that would necessitate moving the object in the container in the general case).
In the case of std::vector, yes, you can manipulate the object simply by dereferencing the iterator. In the case of sorted containers, such as a std::set, you can't do that. Since a set inserts its elements in order, directly manipulating the contents isn't permitted since it might mess up the ordering.
What you have will work. You can also use one of the many STL algorithms to accomplish the same thing.
std::for_each(active.begin(), active.end(), [](Node &n){ n.ax /= n.m; });
Related
I will ask the question first and the motivation next, and finally an illustrative code sample which compiles and executes as expected.
Question
If I can assure myself that an iterator will not get invalidated in the duration when I will be needing to use it, is it safe to hold a pointer to an iterator (e.g. a pointer to a list<int>::iterator).
Motivation
I have multiple containers and I need direct cross references from items held in one container to the corresponding items held in another container and so on. An item in one container might not always have a corresponding item in another container.
My idea thus is to store a pointer to an iterator to an element in container #2 in the element stored in container #1 and so forth. Why? Because once I have an iterator, I can not only access the element in container #2, but if needed, I can also erase the element in container #2 etc.
If there is a corresponding element in container #2, I will store a pointer to the iterator in the element in container #1. Else, this pointer will be set to NULL. Now I can quickly check that if the pointer to the iterator is NULL, there is no corresponding element in container #2, if non-NULL, I can go ahead and access it.
So, is it safe to store pointers to iterators in this fashion?
Code sample
#include <iostream>
#include <list>
using namespace std;
typedef list<int> MyContainer;
typedef MyContainer::iterator MyIterator;
typdef MyIterator * PMyIterator;
void useIter(PMyIterator pIter)
{
if (pIter == NULL)
{
cout << "NULL" << endl;
}
else
{
cout << "Value: " << *(*pIter) << endl;
}
}
int main()
{
MyContainer myList;
myList.push_back(1);
myList.push_back(2);
PMyIterator pIter = NULL;
// Verify for NULL
useIter(pIter);
// Get an iterator
MyIterator it = myList.begin();
// Get a pointer to the iterator
pIter = & it;
// Use the pointer
useIter (pIter);
}
Iterators are generally handled by value. For instance, begin() and end() will return an instance of type iterator (for the given iterator type), not iterator& so they return copies of a value every time.
You can of course take an address to this copy but you cannot expect that a new call to begin() or end() will return an object with the same address, and the address is only valid as long as you hold on to the iterator object yourself.
std::vector<int> x { 1, 2, 3 };
// This is fine:
auto it = x.begin();
auto* pi = ⁢
// This is not (dangling pointer):
auto* pi2 = &x.begin();
It rarely makes sense to maintain pointers to iterators: iterators are already lightweight handles to data. A further indirection is usually a sign of poor design. In your example in particular the pointers make no sense. Just pass a normal iterator.
The problem with iterators is that there are a lot of operations on containers which invalidate them (which one depend on the container in question). When you hold an iterator to a container which belongs to another class, you never know when such an operation occurs and there is no easy way to find out that the iterator is now invalid.
Also, deleting elements directly which are in a container which belongs to another class, is a violation of the encapsulation principle. When you want to delete data of another class, you should better call a public method of that class which then deletes the data.
Yes, it is safe, as long as you can ensure the iterators don't get invalidated and don't go out of scope.
Sounds scary. The iterator is an object, if it leaves scope, your pointer is invalid. If you erase an object in container #2, all iterators may become invalid (depending on the container) and thus your pointers become useless.
Why don't you store the iterator itself? For the elements in container #1 that don't refer to anything, store container2.end().
This is fine as long as iterators are not invalidated. If they are, you need to re-generate the mapping.
Yes it is possible to work on pointers to iterators like it is to other types but in your example it is not necessary since you can simple pass the pass the original iterator as reference.
In general it is not a good idea to store iterators since the iterator may become invalid as you modify the container. Better store the containers and create iterators as you need them.
In the following example a std::list stores objects of type Resource (by value, not pointing to). The Resource class does not provide a less than comparison nor equality operator. What is a good way to remove an object by identity (aka memory address). Can i avoid O(n) somehow? Is std::list the right container?
// Definition of the container
std::list<Resource> resources;
// Code
Resource *closedResource = resourceFromList();
for (std::list<Resource>::iterator it = resources.begin(); it != resources.end(); ++it)
{
if (closedResource == &*it)
{
resources.erase(it);
break;
}
}
Edit: Assume that the Resource class implements move semantic. Furthermore the Resource reregisters itself for any "movement" by a kind of Selector (cp. epoll or java.nio.Selector) for event notifications.
You're storing Resource copies in the container, so later finding an element by address doesn't make much sense.
What you can do is save list::iterators since list has the property that iterators are not invalidated by any operation expect explicitly erasing that iterator (or clearing the entire list).
Edit: Sorry, never mind this answer -- if you are certain only to be removing at most one element, then your loop is fine.
Never mind whether comparing by memory address is sensible, but to use list::erase in a loop you have to write it a little differently to avoid incrementing an invalidated iterator:
for (std::list<Resource>::iterator it = resources.begin(); it != resources.end(); )
{
if (want_to_erase) it = resources.erase(it); // advances to the next position
else ++it;
}
If you have no other requirements than look-up by address, you could always just make a std::set or std::unordered_set of elements and implement Resource::operator<() as pointer comparison.
Either way, there are certain conditions on types for them to be eligible as STL container members; as was asked in the comments, do those conditions apply to your Resource class? Otherwise you could just make a container of std::shared_ptr<Resource> and use its inbuilt comparators, and for example make an std::unordered_set<std::shared_ptr<Resource>>.
"Is std::list the right container?"
I doubt it. If this class does not provide a comparison operator you can still provide one yourself
struct resourcecomparation {
const bool operator() (const Resource &l, const Resource &r) const;
}resourcecomparator;
and then you can use, for instance, an std::set<resource, resourcecomparator>.
I'm in need of a container that has the properties of both a vector and a list. I need fast random access to elements within the container, but I also need to be able to remove elements in the middle of the container without moving the other elements. I also need to be able to iterate over all elements in the container, and see at a glance (without iteration) how many elements are in the container.
After some thought, I've figured out how I could create such a container, using a vector as the base container, and wrapping the actual stored data within a struct that also contained fields to record whether the element was valid, and pointers to the next/previous valid element in the vector. Combined with some overloading and such, it sounds like it should be fairly transparent and fulfill my requirements.
But before I actually work on creating yet another container, I'm curious if anyone knows of an existing library that implements this very thing? I'd rather use something that works than spend time debugging a custom implementation. I've looked through the Boost library (which I'm already using), but haven't found this in there.
If the order does not matter, I would just use a hash table mapping integers to pointers. std::tr1::unordered_map<int, T *> (or std::unordered_map<int, unique_ptr<T>> if C++0x is OK).
The hash table's elements can move around which is why you need to use a pointer, but it will support very fast insertion / lookup / deletion. Iteration is fast too, but the elements will come out in an indeterminate order.
Alternatively, I think you can implement your own idea as a very simple combination of a std::vector and a std::list. Just maintain both a list<T> my_list and a vector<list<T>::iterator> my_vector. To add an object, push it onto the back of my_list and then push its iterator onto my_vector. (Set an iterator to my_list.end() and decrement it to get the iterator for the last element.) To lookup, look up in the vector and just dereference the iterator. To delete, remove from the list (which you can do by iterator) and set the location in the vector to my_list.end().
std::list guarantees the elements within will not move when you delete them.
[update]
I am feeling motivated. First pass at an implementation:
#include <vector>
#include <list>
template <typename T>
class NairouList {
public:
typedef std::list<T> list_t;
typedef typename list_t::iterator iterator;
typedef std::vector<iterator> vector_t;
NairouList() : my_size(0)
{ }
void push_back(const T &elt) {
my_list.push_back(elt);
iterator i = my_list.end();
--i;
my_vector.push_back(i);
++my_size;
}
T &operator[](typename vector_t::size_type n) {
if (my_vector[n] == my_list.end())
throw "Dave's not here, man";
return *(my_vector[n]);
}
void remove(typename vector_t::size_type n) {
my_list.erase(my_vector[n]);
my_vector[n] = my_list.end();
--my_size;
}
size_t size() const {
return my_size;
}
iterator begin() {
return my_list.begin();
}
iterator end() {
return my_list.end();
}
private:
list_t my_list;
vector_t my_vector;
size_t my_size;
};
It is missing some Quality of Implementation touches... Like, you probably want more error checking (what if I delete the same element twice?) and maybe some const versions of operator[], begin(), end(). But it's a start.
That said, for "a few thousand" elements a map will likely serve at least as well. A good rule of thumb is "Never optimize anything until your profiler tells you to".
Looks like you might be wanting a std::deque. Removing an element is not as efficient as a std::list, but because deque's are typically created by using non-contiguous memory "blocks" that are managed via an additional pointer array/vector internal to the container (each "block" would be an array of N elements), removal of an element inside of a deque does not cause the same re-shuffling operation that you would see with a vector.
Edit: On second though, and after reviewing some of the comments, while I think a std::deque could work, I think a std::map or std::unordered_map will actually be better for you since it will allow the array-syntax indexing you want, yet give you fast removal of elements as well.
I'm having a std::vector with elements of some class ClassA. Additionally I want to create an index using a std::map<key,ClassA*> which maps some key value to pointers to elements contained in the vector.
Is there any guarantee that these pointers remain valid (and point to the same object) when elements are added at the end of the vector (not inserted). I.e, would the following code be correct:
std::vector<ClassA> storage;
std::map<int, ClassA*> map;
for (int i=0; i<10000; ++i) {
storage.push_back(ClassA());
map.insert(std::make_pair(storage.back().getKey(), &(storage.back()));
}
// map contains only valid pointers to the 'correct' elements of storage
How is the situation, if I use std::list instead of std::vector?
Vectors - No. Because the capacity of vectors never shrinks, it is guaranteed that references, pointers, and iterators remain valid even when elements are deleted or changed, provided they refer to a position before the manipulated elements. However, insertions may invalidate references, pointers, and iterators.
Lists - Yes, inserting and deleting elements does not invalidate pointers, references, and iterators to other elements
As far as I understand, there is no such guarantee. Adding elements to the vector will cause elements re-allocation, thus invalidating all your pointers in the map.
Use std::deque! Pointers to the elements are stable when only push_back() is used.
Note: Iterators to elements may be invalidated! Pointers to elements won't.
Edit: this answer explains the details why: C++ deque's iterator invalidated after push_front()
I'm not sure whether it's guaranteed, but in practice storage.reserve(needed_size) should make sure no reallocations occur.
But why don't you store indexes?
It's easy to convert indexes to iterators by adding them to the begin iterator (storage.begin()+idx) and it's easy to turn any iterator into a pointer by first dereferencing it, and then taking its address (&*(storage.begin()+idx)).
Just make them both store pointers an explicitly delete the objects when you don't need them.
std::vector<ClassA*> storage;
std::map<int, ClassA*> map;
for (int i=0; i<10000; ++i) {
ClassA* a = new ClassA()
storage.push_back(a)
map.insert(std::make_pair(a->getKey(), a))
}
// map contains only valid pointers to the 'correct' elements of storage
From one of the comments to another answer, it seems as if all that you want is centralize (ease) memory management. If that is really the case, you should consider using prepackaged solutions like the boost pointer container library and keep your own code as simple as possible.
In particular, take a look at ptr_map
for vectors no.
for lists yes.
how?
iterator works as a pointer to a particular node in the list.
so you can assign values to any struct like:
list mylist;
pair< list::iterator ,int > temp;
temp = make_pair( mylist.begin() , x );
What are Iterators in C++?
Iterators are a way of traversing a collection of objects. Typically, they allow you to access an STL (Standard Template Library) container sequentially in ways similar to accessing a classical C array with a pointer. To access an object through an iterator, you dereference it like a C pointer. To access the next object in a collection, you use the increment (++) operator. Some containers have multiple kinds of iterators that allow you to traverse the collection in different ways.
Though it initially seems fairly obvious, this is actually a rather deeper question than you may realize. Along with Paul McJones, Alexander Stepanov (designer of the original, for anybody who's not aware of that) recently released a book named Elements of Programming (aka EOP). The entirety of chapter six in that book is devoted specifically to iterators, and quite a bit of the rest of the book relates closely to iterators as well. Anybody who really wants to know iterators in full detail might consider reading this book.
Warning: EOP is not for the faint of heart. It's relatively short (~260 pages), but quite dense. Speaking from experience, the early going is a bit disconcerting. My initial reaction to the first chapter was more or less "well, this is so obvious it's hardly worth reading. I did start programming before last week, after all!"
Fortunately, I did look at the exercises, and tried to do a couple -- and even though I had thought of the subjects as obvious, the exercises demand rigorous proofs. It's a bit like being asked to prove (in a mathematical sense) that water is wet. You end up just about needing to read the chapter a couple of times just to get past your own preconceived notion that you already know the answers, so you can look at the real question -- what does "wet" really mean; what are the fundamental characteristics of "wetness"?
http://en.wikipedia.org/wiki/Iterator
Something that lets you go through everything in an array, one by one.
In c++, i think you're talking about "for_each" ... As far as I know, C++ doesn't actually have "foreach" unlike languages like C#. However, the standard template library has it.
From p. 80 of Accelerated C++:
An iterator is a value that
Identifies a container and an element in the container
Lets us examine the value stored in that element
Provides operations for moving between elements in the container
Restricts the available operations in ways that correspond to what the container can handle efficiently
They're a representation of a position within a sequence. On their own they're little more than curiosities, but when dereferenced they result in the value contained within the sequence at the position it represents.
If you come from higher-level languages like Java or Python, you may have noticed C++ doesn't have any built-in complex types but only primitives like int, double or char. Since C++ was designed to be extremely efficient, whenever you need to use any collection type that is used to hold other values, it makes sense to create a new custom class. In fact, this is the way how C++ combines lower-level control and higher-level abstractions.
The Standard Template Library provides a standartised collection of those classes that you can use to hold multiple values under a single entity. Primarily, they were created because raw C arrays are not flexible enough and the containers provide developers with smoother developer experience as they:
dynamically expand and shrink without any developer effort;
provide multiple useful interfaces with the data (size(), upper_bound(), etc);
simplify memory management with Resource Acquisition is Initialisation.
So far, so good. Standard containers like vector or list give developers greater flexibility without much performance loss. However, since they are custom classes defined with C++ semantics, they need to provide also a way to access the data they hold. One could argue a simple operator[] or next() method could do the trick, and indeed you can do this, however the STL took inspiration from C and created a way to be able to access container items not depending on the container object itself: iterators.
Under the hood, iterator is nothing but an object that wraps a pointer to a value with a few operator overloading. You can use iterators in a similar way how you use pointers to array:
you can pass iterators around and iterate through containers even if you don't have the access to the container objects themselves;
you can dereference and move iterator with incrementation.
This is the primary purpose of iterators: to serve as pointers to container items. Because different containers store different items in different ways (std::vector uses contiguous block of memory, std::list stores nodes elsewhere connected with pointers, std::map uses hashing key in associative array), iterators are useful to provide a common interface that will be implemented in every separate container. In fact, this is the very reason that allows containers like std::vector, std::array or std::map to be enumerated with range-based for loops:
std::vector<int> grades = {4, 5, 1, 8, 10};
for (int grade : grades) std::cout << grade << " ";
//-> 4 5 1 8 10
This for loop is just syntactic sugar for using iteration:
std::vector<int> grades = {4, 5, 1, 8, 10};
std::vector::iterator it = grades.begin();
for (; it != grades.end(); ++it) std::cout << grade << " ";
//The output is the same.
You may have noticed some common interfaces iterators use, precisely they:
overload the * operator to dereference an item;
overload the ++ operator to move the iterator one item forward;
overload the == and != operators to compare if they point to the same value;
are usually defined as a nested friend class (you access them with <container>::iterator, although you can entirely define iterator as a separate class.
Notice also that all containers that support containers should provide begin() method that returns the iterator to the first item, as well as end() to return an iterator to the item after the last one. The reason why it points to the location past the final one is because it is used to evaluate if the iterator exhausted all items: had end() pointed to the last item, the looping condition would be it <= grades.end(). Instead pointing to the next location after the container allows it evaluate it with a simple less check, which is the same reason why arrays begin with zero. Aside from them, there's also rbegin() and rend() functions that provide reversed iterator that goes from the end to the start and its ++ operator actually goes to the beginning.
Implementing a custom iterator
To make it completely clear, let's implement our own custom iterator for a wrapper around plain arrays.
template<typename T, unsgined int Capacity> class Array {
T data[Capacity];
int count;
friend class Iterator;
public:
Array(const std::initializer_list args) {
for (int step = 0; step < args.size(); step++)
data[step] = args[step;
}
int size() : count;
T& operator[](int index) {
if (index < 0 || index > capacity) throw
std::out_of_range("Index out of range.");
return data[index];
}
Iterator<T> begin() {
return &data; //Pointer to array yield the
//address to their first item.
}
Iterator<T> end() {
return &(data + Capacity);
}
};
template<typename T> class Iterator {
T* reference;
public:
Iterator(const Array<T>& array) {
reference = array.begin();
}
T* operator*() {
return reference;
}
Iterator<T> operator++() {
return ++reference; //This is array-specific implementation detail.
}
bool operator!=(const Iterator<T>& other) : *reference != *other;
};
int main() {
Array<int> array = {4, 5, 10, 12, 45, 100};
Iterator<int> it = array.begin();
while (it != array.end()) {
std::cout << *it;
++it;
}
return 0;
}
As you can see, dividing iterator as a separate class creates a need to specify its type separately as well, which is the reason why it's usually defined as a nested class in its container.
There is also <iterator> header that provides some useful facilities for standard iterators, such as:
next() function that increments the iterator;
prev() function that returns the iterator ` step before;
advance(int) that moves iterator n steps forward;
overloaded operators to compare iterators;
other iteration-related additions.
If you need to write a custom iterator for your own highly-specific container that isn't present in STL, you should remember that iterators are used as a median between containers and algorithms, and for your own container you should pick the proper type of iterator (input, output, forward, bidirectional or random access) to support a number of standard algorithms out of the hand.