If I have a vector of objects (plain objects, not pointers or references), why can't I do this?
Object* object;
object = vectorOfObjects.end();
or
object = &vectorOfObjects.end();
or
object = &(*vectorOfObjects.end());
also the same question if 'object' was a reference.
They are three separate errors:
object = vectorOfObjects.end();
won't work because end() returns a an iterator, and object is a pointer. Those are generally distinct types (A vector can use raw pointers as iterators, but not all implementations do it. Other containers require special iterator types).
object = &vectorOfObjects.end();
doesn't work because you take the address of the returned iterator. That is, you get a pointer to an iterator, rather than a pointer to an Object.
object = &(*vectorOfObjects.end());
doesn't work because the end iterator doesn't point to a valid element. It points one past the end of the sequence. And so, it can't be dereferenced. You can dereference the last element in the sequence (which would be --vectorOfObjects.end()), but not an iterator pointing past the end.
Finally, the underlying problem/confusion might be that you think an iterator can be converted to a pointer. In general, it can't. If your container is a vector, you're guaranteed that elements are allocated contiguously, like in an array, and so a pointer will work. But for, say, a list, a pointer to an element is useless. It doesn't give you any way to reach the next element.
Because .end() returns an iterator, not an Object, which isn't even a valid member of the vector.
Even using begin(), which returns a valid object, you'd need the following:
The correct way would be:
std::vector<Object> vec;
std::vector<Object>::iterator it;
//....
it = vec.begin();
Object o = *it;
This is because by convention end does not point to a valid location in the container: it sits at a location one past the end of the container, so dereferencing it is illegal.
The situation with begin() is different: you can dereference it when v.begin() != v.end() (i.e. when the container is not empty):
object = *vectorOfObjects.begin();
If you need to access the last element, you can do this:
vector<object>::const_iterator i = vectorOfObjects.end();
i--;
cout << *i << endl; // Prints the last element of the container
Again, this works only when your vector contains at least one element.
Object* means a pointer to an Object, where a pointer is a memory address. But the .end() method returns an Iterator, which is an object itself, not a memory address.
Related
I need to return a pointer to some value in my list
std::vector<std::list<int>> lists;
...
if(lists.at(i).front()==val){
//return a pointer after the first value
return ptr;
}
The best way i can think of is using std::next, but i have no idea how to make it returns a pointer
The best way i can think of is using std::next, but i have no idea how to make it returns a pointer
std::next returns an iterator. You can use the indirection operator to get the pointed object. You can use the addressof operator to get the memory address (i.e. a pointer) of that object. So:
auto it = whatever; // iterator to the object whose pointer you want
return &*it; // return the pointer
Not relevant to int, but for some rare cases, you may need to use std::addressof in case the the type has an overloaded addressof operator.
Also, I recommend considering whether it makes any sense to return a pointer rather than the iterator itself.
I think of a function like this:
std::list<int>::iterator get(std::vector<std::list<int>>& lists, int i,int val)
{
assert(i<lists.size());
if(lists.at(i).front()==val)
{
//return a pointer after the first value
std::list<int>::iterator it = lists.at(i).begin();
return it++;
}
return lists.at(i).end();
}
Iterators are just "better" pointers. That is, you can use them as pointers (access value by dereferencing them)
auto it = lists.at(i).begin() // returns iterator to first element in i-th list in vector
...
*it // you can access value as if "it" was pointer
it++; // iterators can be "moved", that is, they will point to next element than before
if you really wish to return pointer type *int, instead of std::list<int>::iterator, you dereference it and gain reference back again
return &(*it);
for more on iterators, you can look here. You can see that there are many types of iterators, but all can be dereference as if they were pointers.
std::list<>:iterator is bidirectional iterator (they don't have random access, but you can move them by one element at a time, forward or backward)
std::list<Value> stdList;
stdList.push_back(Value());
Value * ptr = &stdList.back(); // <-- what will this address point to?
If I take the reference returned by back() and implicitly convert it to the less generic Value *, will it point to the last value of the list, or will it point to someplace unexpected?
And is there a way to create an iterator from a pointer, for use with std::list functions such as erase()? I realize generic to specific (iterator to pointer) is far more feasible than going the other direction, but I thought I'd ask anyway.
The pointer will point to the value as it is stored inside the container. The reference did the same thing.
You can't turn that pointer into a list iterator directly, because you've lost all the information about the surrounding structure. To do this you would have to get clever with list::find.
What you are trying to do it is sometimes done using vector. The reason you can turn a vector data element pointer into an iterator (array index) is because you know the structure of a vector.
Please note that list::back() does not return an iterator. It returns a reference. The two are quite different. Are you thinking about list::end()? Or are you genuinely confused between iterators and references? Because you can get a reference from a pointer. You do it like this:
Value& refval = *ptr;
Yes, The pointer point to the last value stored in the list.
We can not create an iterator from a pointer, iterator is a concept for the container (list here), and iterator don't care about what kind of value stored on the list.
Reference and pointer are handle for the value stored on the list, they are interchangeable, we can convert a reference to a pointer and vice versa.
I have an (uncommented...) source file which I'm trying to understand.
static const Map *gCurMap;
static std::vector<Map> mapVec;
then
auto e = mapVec.end();
auto i = mapVec.begin();
while(i!=e) {
// ...
const Map *map = gCurMap = &(*(i++));
// ...
}
I don't understand what &(*(i++)) does. It does not compile when just using i++, but to me it looks the same, because I'm "incrementing" i, then I'm requesting the value at the given address and then I'm requesting the address of this value?!
Not at all. &*x is the same as operator&(operator*(x)), which can be anything you want.
It is only true for pointer types like T * p that &*p is the same as p. But C++ has user-defined types and overloadable operators.
The dereference operator (*) is typically overloaded for iterators to return a reference to the container element. The effect of the ampersand operator (&) on the container element is up to the class author; if you want to take the address unconditionally, you should use std::addressof(*i++) (from your favourite header<memory>).
mapVec.begin() returns an iterator which has an overloaded operator++. The "dereference" (overloaded operator*) of the iterator is to get to the map object. The reference & is, well, because map is a pointer, so it's being assigned to the address of the object from the dereference of i. We can't do simply i++ because it would still be an iterator, and not the actual map object.
i is an iterator, *i is the object pointed to by that iterator, and &*i is the address of that object. If the iterator were just a plain old pointer, this would be unnecessary, but usually it's not so simple. The iterator is often of some class type that overloads operator* to allow you to access the object it is pointing at. So this is basically a conversion from an iterator to an element to a pointer to that element.
I would move the increment to the next line because it just makes the given line harder to understand. This would be equivalent because the value of i++ is just i and the increment happens afterwards.
It isn't the same: i is an iterator. Dereferencing an iterator yields a reference to some object, i.e., a T& for some type T. Taking the address of such an object yields a T*, i.e., the address of the object at the location i. That the iterator is also incremented in the same expression is just a detail and likely to be a Bad Idea (post increment is typically less efficient than preincrement and there is no real need to post increment the iterator in the code excerpt: it can as well be pre incremented at some other location).
typedef struct value
{
char* contents;
int size;
}Value;
hash_map<Key,list<Value>,hash<Key>,eqKey> dspace;
hash_map<Key, list<Value>, hash<Key>, eqKey>::iterator itr;
list<Value> vallist;
list<Value>::iterator valitr;
Value * ptr;
itr=dspace.find(searchKey);
valitr=(itr->second).begin();
valitr++;
ptr=&*valitr;
here ptr pointer is pointing to the address of the element pointed by the valitr iterator. Now I want to erase this element from the list using this pointer. I have found that list.erase function do this but I have to provide the position or iterator .
Please give me some idea how I can erase this element using pointer instead of going through the list .
valitr denotes the position in the list. *valitr dereferences the iterator, giving you a reference to the value data of that pointer, which no longer has any reference to the list it is stored in.
If you need indeed erase a certain element in the list, and not just go for the 2nd element, you have to scan the list (from begin() to end(), and check the condition for finding the element, and use erase using the iterator to that element.
The API of the list does not intend to have elements deleted by pointer. You need the iterator.
Depending on the implementation you are using, there might be ways to get the element's interator from a pointer, but that is not guaranteed. And it might change later.
Try to keep the iterator somehow.
I have a vector like so:
vector<MyType*> _types;
And I want to iterate over the vector and call a function on each of MyTypes in the vector, but I'm getting invalid return errors from the compiler. It appears the pos iterator isn't a pointer to MyType, it's something else. What am I not understanding?
Edit: Some code..
for (pos = _types.begin(); pos < _types.end(); pos++)
{
InternalType* inst = *pos->GetInternalType();
}
The compiler errors are:
invalid return type 'InternalType**' for overloaded 'operator ->'
'GetInternalType' : is not a member of 'std::_Vector_iterator<_Ty,_Alloc>'
Edit pt2
Should my vector contain pointers or objects? What are the pros and cons? If I am using new to create an instance, I am guessing I can only use a vector of pointers to MyType is that correct?
If the vector contained objects, not pointers, you could do pos->foo(). The iterator "acts like" a pointer. But your vector contains pointers, so an iterator will act like a pointer to a pointer, so needs to be dereferenced twice.
MyType *pMyType = *pos; // first dereference
if (pMyType) { // make sure the pointer is not null
pMyType->foo(); // second dereference
}
If you are sure the pointer is not null, you could do this:
(*pos)->foo();
The parenthesis around *pos are needed so the dereference applies to pos, not to pos->foo(). Order of operations.
If your vector needs to contain items from a class hierarchy (e.g., subclasses of MyType), then you have to make it a vector of pointers. Otherwise a vector of objects is probably simpler.
You've defined _types as a vector of pointers. Assuming your pos is an iterator into that vector, it's going to be an iterator to a pointer, so you'll need to dereference it twice to get to an instance of MyType.
Edit: based on what you've added to the question: You have something like *pos->whatever. Try (*pos)->whatever instead. As it stands, you're trying to use whatever as a member of the iterator, then dereference the result...
Iterators are not pointers. Iterators are types that behave like pointers. In some implementations of some containers, the iterator type may in fact be a pointer (all pointers are iterators), but this cannot be used as a general rule.
If you need to generate a pointer from an iterator, you can use &*pos, which will dereference the iterator and then get the address of the result (of course, this doesn't work if unary operator & is overloaded, but that's a whole other can of worms).
for (vector<MyType*>::iterator i = _tpes.begin(); i != _types.end(); ++i) {
// do something with i
}
for (vector<MyType*>::iterator it = _types.begin();
it != _types.end();
++it)
{
// `*it` is this iteration's `MyType*` from your vector
}