Isn't an Iterator in c++ a kind of a pointer? - c++

Ok this time I decided to make a list using the STL. I need to create a dedicated TCP socket for each client. So everytime I've got a connection, I instantiate a socket and add a pointer to it on a list.
list<MyTcp*> SocketList; //This is the list of pointers to sockets
list<MyTcp*>::iterator it; //An iterator to the list of pointers to TCP sockets.
Putting a new pointer to a socket was easy, but now every time the connection ends I should disconnect the socket and delete the pointer so I don't get a huge memory leak, right? well.. I thought I was doing ok by setting this:
it=SocketList.begin();
while( it != SocketList.end() ){
if((*it)->getClientId() == id){
pSocket = it; // <-------------- compiler complains at this line
SocketList.remove(pSocket);
pSocket->Disconnect();
delete pSocket;
break;
}
}
But the compiler is saying this:
error: invalid cast from type ‘std::_List_iterator<MyTcp*>’ to type ‘MyTcp*’
Can someone help me here? i thought I was doing things right, isn't an iterator at any given time just pointing to one of the elements of the set? how can I fix it?

Try this:
pSocket = *it;
Iterators act a lot like pointers, but in reality they can be a pointer or a full-fledged class that acts like one. The important thing in this case, is that when you dereference one, you get whatever item is being stored in the container. Since you are storing MyTcp*s in the list, when you dereference the iterator you get a MyTcp*. pSocket is of type MyTcp* so the assignment above succeeds. The assignment you are trying to do is not dereferencing the iterator -- you are trying to assign the iterator itself to pSocket.
It's kind of like the following case:
void foo()
{
MyTcp *array[10]; // An array full of MyTcp pointers
MyTcp **iterator = NULL; // pointers make good iterators for arrays (but not for std::lists)
for (iterator = array; iterator != array + 10; ++iterator)
{
// This fails to compile (cannot assign MyTcp** to MyTcp*:
MyTcp *wrong = iterator;
// This succeeds:
MyTcp *current = *iterator; // important to dereference the iterator
}
}

An iterator is a generalization of a pointer. There's a good article in Wikipedia on the Iterator Pattern.
The reason iterators are used in the STL is to make algorithms orthogonal to containers. Any container can be used with (nearly) any algorithm as long as that container supports iterators.

An iterator might be implemented by a pointer (in the case of vector, it is). Iterators do have pointer semantics - you dereference them to get at the value.
But you're storing pointers in the list. The "MyTcp*" is your value, so to assign it, you dereference "it".
pSocket = *it;

An iterator does just point to one of the elements, and the syntax for dereferencing it is the same, but it's a different type (with a different in-memory representation), and pointer arithmetic on it does something different than it does on a pointer (i.e. the result of iterator arithmetic points to a different memory location than you'd get if you converted the iterator to a pointer and did pointer arithmetic), so you usually don't want to confuse the two types.
However, given the types that your list is a list of pointers, and you're only dereferencing pSocket once in the pSocket->Disconnect(); call, I think Eclipse's answer is what you want: pSocket = *it;

Related

How to access the first element of std::list?

I have a list std::list<T *> *l;. this list is not null and has some values. My problem is how to access items properly? i do not need to iterate over the list. i just want the first item only.
std::list<T*>::iterator it = l->begin();
if (it != l->end())
{
// accessing T
int value = (*it)->value(); // Is this safe?
}
or should i check for null also?
if (it != l->end() && (*it))
{
// accessing T
int value = (*it)->value();
}
If you are forced to use std::list<T*> myList; and let's say that T is defined as:
struct T
{
T(const char* cstr) : str(cstr){ }
std::string str;
};
then just use std::list::front to access first element:
std::string firstStr = myList.front()->str;
Note that in this case myList.front() returns a reference to first element in your list, which is reference to pointer in this case. So you can treat it just like a pointer to the first element.
And to your question about the NULL: When you work with the container of pointers, the pointer should be removed from the container once the object is destructed. Once you start using pointers, it usually means that you are the one who becomes responsible for the memory management connected with objects that these pointers point to (which is the main reason why you should prefer std::list<T> over std::list<T*> always when possible).
Even worse than NULL pointers are dangling pointers: When you create an object, store its address in your container, but you will not remove this address from your container once the object is destructed, then this pointer will become invalid and trying to access the memory that this pointer points to will produce undefined behavior. So not only that you should make sure that your std::list doesn't contain NULL pointers, you should also make sure it contains only pointers to valid objects that still exist.
So by the time you will be cleaning up these elements, you will find yourself removing pointers from your list and deleting objects they point to at once:
std::list<T*> myList;
myList.push_back(new T("one"));
myList.push_back(new T("two"));
myList.push_back(new T("three"));
myList.push_back(new T("four"));
while (!myList.empty())
{
T* pT = myList.front(); // retrieve the first element
myList.erase(myList.begin()); // remove it from my list
std::cout << pT->str.c_str() << std::endl; // print its member
delete pT; // delete the object it points to
}
It's also worth to read these questions:
Can you remove elements from a std::list while iterating through it?
Doesn't erasing std::list::iterator invalidates the iterator and destroys the object?
The need for a null-check of the list element depends entirely on what can be put into the list in the first place.
If it is possible that the list contains null pointers, then you most definitely should check for for NULL before accessing the element.
If it is not possible, then there is also no reason to check.

Is it safe to hold pointers to iterators in C++?

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 = &it;
// 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.

Understanding const_iterator with pointers?

I'm trying to understand what const_iterator means. I have the following example code:
void CustomerService::RefreshCustomers()
{
for(std::vector<Customer*>::const_iterator it = customers_.begin();
it != customers_.end() ; it ++)
{
(*it)->Refresh();
}
}
Refresh() is a method in the Customer class and it is not defined as const. At first thought I thought const_iterator was supposed to disallow modification to the elements of the container. However, this code compiles without complaint. Is this because there's an extra level of indirection going on? What exactly does const_iterator do/mean?
UPDATE
And in a situation like this, is it best practice to use const_iterator?
A const_iterator over a vector<Customer*> will give you a Customer * const not a Customer const*. So you cannot actually change the value being iterated (a pointer), but you sure can change the object pointed to by it. Basically all it says in your case is that you can't do this:
*it = ..something..;
You're not modifying the contents of the container. The contents of the container are just pointers. However, you can freely modify whatever the pointers point to.
If you didn't want to be able to modify what the pointers point to, you'd need a vector<const Customer*>.
const_iterator is not about whether you can modify the container or not, but about whether you can modify the objects in the container or not. In your case the container contains pointers, and you cannot modify the pointers themselves (any more than you could modify integers...) You can still make call to non-const Refresh() behind a pointer from the collection, because that call does not change the pointer itself.
Difference between const_iterator and iterator is important [only] when your container contains e.g. class instances, not pointers to them, but the instances themselves, for example in a container
list < pair < int , int > >
If 'it' is a const_iterator into this list, you can't do
it->first = 5
but if it is iterator (not const_iterator), that works.

Vector iterators

I have a the following code.
vector<IRD>* irds = myotherobj->getIRDs();//gets a pointer to the vector<IRD>
for(vector<IRD>::iterator it = irds->begin(); it < irds->end(); it++)
{
IRD* ird = dynamic_cast<IRD*>(it);
ird->doSomething();
//this works (*it).doSomething();
}
This seems to fail...I just want to get the pointer to each element in the vector without using (*it). all over.
How do I get the pointer to the object?
When I iterate over the vector pointer irds, what exactly am I iterating over? Is it a copy of each element, or am I working with the actual object in the vector when I say (*it).doSomething(),
Why do you want to get a pointer?
Use a reference:
for(vector<IRD>::iterator it = irds->begin(); it != irds->end(); ++it)
{
IRD & ird = *it;
ird.doSomething();
}
Alternatively:
for(vector<IRD>::iterator it = irds->begin(); it != irds->end(); ++it)
{
it->doSomething();
}
Also, as everyone said, use != when comparing iterators, not <. While it'll work in this case, it'll stop working if you use a different container (and that's what iterators are for: abstracting the underlying container).
You need to use != with iterators to test for the end, not < like you would with pointers. operator< happens to work with vector iterators, but if you switch containers (to one like list) your code will no longer compile, so it's generally good to use !=.
Also, an iterator is not the type that it points to, so don't try to cast it. You can use the overloaded operator-> on iterators.
vector<IRD>* irds = myotherobj->getIRDs();//gets a pointer to the vector<IRD>
for(vector<IRD>::iterator it = irds->begin(); it != irds->end(); ++it)
{
it->dosomething();
}
Dereference the iterator to get a reference to the underlying object.
vector<IRD>* irds = myotherobj->getIRDs();
for(vector<IRD>::iterator it = irds->begin(); it != irds->end(); ++it)
{
IRD& ird = *it;
ird.doSomething();
// alternatively, it->doSomething();
}
First consider whether you actually need a pointer to the element or if you're just trying to kind of use iterators but kind of avoid them. It looks like you're trying to code C in C++, rather than coding C++. In the example you gave, it seems like rather than converting to a pointer and then working with that pointer, why not just use the iterator directly? it->doSomething() instead of ird->doSomething().
If you're thinking that you need to save that pointer for later to use on the vector after doing some work, that's potentially dangerous. Vector iterators and pointers to elements in a vector can both be invalidated, meaning they no longer point to the vector, so you are basically attempting to use memory after you've freed it, a dangerous thing to do. A common example of things that can invalidate an iterator is adding a new element. I got into the mess of trying to store an iterator and I did a lot of work to try to make it work, including writing a "re_validate_iterator()" function. Ultimately, my solution proved to be very confusing and didn't even work in all cases, in addition to not being scalable.
The solution to trying to store the position of the vector is to store it as an offset. Some integer indicating the position within the vector that your element is at. You can then access it with either myvector.begin() + index if you need to work with iterators, or myvector.at (index) if you want a reference to the element itself with bounds checking, or just myvector [index] if you don't need bounds checking.
You can get a pointer from an iterator by doing &*it. You get a pointer to the actual IRD object stored inside the vector. You can modify the object through the pointer and the modification will "stick": it will persist inside the vector.
However, since your vector contains the actual objects (not pointers to objects) I don't see any point in dynamic_cast. The type of the pointer is IRD * and it points to IRD object.
The only case when the dereferenced iterator might refer to a copy (or, more precisely, to a proxy object) is vector<bool>, which might be implemented as a bit-vector.
When I iterate over the vector pointer irds, what exactly am I iterating over? Is it a copy of each element, or am I working with the actual object in the vector when I say (*it).doSomething(),
When you iterate over a vector you work with the object itself, not a copy of it.
The usual idiom is &*it to get a pointer. Dynamic casts have nothing to do with it.

Returning a pointer to a vector element in c++

I have a vector of myObjects in global scope.
I have a method which uses a std::vector<myObject>::const_iterator to traverse the vector, and doing some comparisons to find a specific element.
Once I have found the required element, I want to be able to return a pointer to it (the vector exists in global scope).
If I return &iterator, am I returning the address of the iterator or the address of what the iterator is pointing to?
Do I need to cast the const_iterator back to a myObject, then return the address of that?
Return the address of the thing pointed to by the iterator:
&(*iterator)
Edit: To clear up some confusion:
vector <int> vec; // a global vector of ints
void f() {
vec.push_back( 1 ); // add to the global vector
vector <int>::iterator it = vec.begin();
* it = 2; // change what was 1 to 2
int * p = &(*it); // get pointer to first element
* p = 3; // change what was 2 to 3
}
No need for vectors of pointers or dynamic allocation.
Returning &iterator will return the address of the iterator. If you want to return a way of referring to the element return the iterator itself.
Beware that you do not need the vector to be a global in order to return the iterator/pointer, but that operations in the vector can invalidate the iterator. Adding elements to the vector, for example, can move the vector elements to a different position if the new size() is greater than the reserved memory. Deletion of an element before the given item from the vector will make the iterator refer to a different element.
In both cases, depending on the STL implementation it can be hard to debug with just random errors happening each so often.
EDIT after comment: 'yes, I didn't want to return the iterator a) because its const, and b) surely it is only a local, temporary iterator? – Krakkos'
Iterators are not more or less local or temporary than any other variable and they are copyable. You can return it and the compiler will make the copy for you as it will with the pointer.
Now with the const-ness. If the caller wants to perform modifications through the returned element (whether pointer or iterator) then you should use a non-const iterator. (Just remove the 'const_' from the definition of the iterator).
You can use the data function of the vector:
Returns a pointer to the first element in the vector.
If don't want the pointer to the first element, but by index, then you can try, for example:
//the index to the element that you want to receive its pointer:
int i = n; //(n is whatever integer you want)
std::vector<myObject> vec;
myObject* ptr_to_first = vec.data();
//or
std::vector<myObject>* vec;
myObject* ptr_to_first = vec->data();
//then
myObject element = ptr_to_first[i]; //element at index i
myObject* ptr_to_element = &element;
It is not a good idea to return iterators. Iterators become invalid when modifications to the vector (inversion\deletion ) happens. Also, the iterator is a local object created on stack and hence returning the address of the same is not at all safe. I'd suggest you to work with myObject rather than vector iterators.
EDIT:
If the object is lightweight then its better you return the object itself. Otheriwise return pointers to myObject stored in the vector.
As long as your vector remains in global scope you can return:
&(*iterator)
I'll caution you that this is pretty dangerous in general. If your vector is ever moved out of global scope and is destructed, any pointers to myObject become invalid. If you're writing these functions as part of a larger project, returning a non-const pointer could lead someone to delete the return value. This will have undefined, and catastrophic, effects on the application.
I'd rewrite this as:
myObject myFunction(const vector<myObject>& objects)
{
// find the object in question and return a copy
return *iterator;
}
If you need to modify the returned myObject, store your values as pointers and allocate them on the heap:
myObject* myFunction(const vector<myObject*>& objects)
{
return *iterator;
}
That way you have control over when they're destructed.
Something like this will break your app:
g_vector<tmpClass> myVector;
tmpClass t;
t.i = 30;
myVector.push_back(t);
// my function returns a pointer to a value in myVector
std::auto_ptr<tmpClass> t2(myFunction());
Say, you have the following:
std::vector<myObject>::const_iterator first = vObj.begin();
Then the first object in the vector is: *first. To get the address, use: &(*first).
However, in keeping with the STL design, I'd suggest return an iterator instead if you plan to pass it around later on to STL algorithms.
You are storing the copies of the myObject in the vector. So I believe the copying the instance of myObject is not a costly operation. Then I think the safest would be return a copy of the myObject from your function.
Refer to dirkgently's and anon's answers, you can call the front function instead of begin function, so you do not have to write the *, but only the &.
Code Example:
vector<myObject> vec; //You have a vector of your objects
myObject first = vec.front(); //returns reference, not iterator, to the first object in the vector so you had only to write the data type in the generic of your vector, i.e. myObject, and not all the iterator stuff and the vector again and :: of course
myObject* pointer_to_first_object = &first; //* between & and first is not there anymore, first is already the first object, not iterator to it.
I'm not sure if returning the address of the thing pointed by the iterator is needed.
All you need is the pointer itself. You will see STL's iterator class itself implementing the use of _Ptr for this purpose. So, just do:
return iterator._Ptr;