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.
Related
When we use iterator we declare iterator and then itr as an object, but we don't pass any pointer like we do every time when declaring pointer variable but when we print the value of vector by the use of iterator than how itr became*itr
when we doesn't pass any pointer
Is pointer is hidden or its work on the background?
Example like:
iterator itr;
*itr
How it works does * means any other things to iterator or *itr act like normal pointer variable.
If it works like a pointer variable then why we do not pass * when declaring itr.
An iterator is an object that lets you travel (or iterate) over each object in a collection or stream. It is a sort of generalization of pointers. That is, pointers are one example of an iterator.
Iterators implement concepts required by various algorithms such as forward iteration (meaning it can be incremented to move forward in the collection), bi-directional iteration (meaning it can go forward and backward), and random access (meaning you can use an index an arbitrary item in the collection).
For instance, moving backward can't typically happen in a stream, so stream's iterators are typically forward iterators only because once you access a value, you can't go back in the stream. A linked list's iterators are bi-directional because you can move forward or backward, but you cannot access them by indexing because the nodes are not typically in contiguous memory, so you can't calculate with an index where an arbitrary element is. A vector's iterators are random access and very much like pointers. (C++20 made these categories more precise, so the old categories are now called "Legacy".)
Iterators can also have special functions, such as std::back_inserter, which appends items to the end of a container when a value is assigned to it's referrent.
So, you can see that iterators allow you to be more precise in defining what your consumer of iterators expects. If your algorithm requires bi-directional iteration, you can communicate that and limit it so it won't work with forward-only iterators.
As for the * operator, it is similar to the * operator for a pointer. In both cases, it means, "give me the value referred to by this handle". It is implemented via operator overloading. You do not need the * when declaring an iterator because it is not a pointer, which is a lower-level construct in the language. Rather, it is an object with pointer-like semantics.
To answer your questions below:
No, the * is not automatically created. When you declare an iterator you are declaring an object. When the class for that object is defined, it may or may not have an operator overload for the * operator (or the == or the + or any other operators).
When you go to use the object, such as passing it to a function, the types will need to match up. If a function you were passing it to requires an iterator (e.g. std::sort()), then no dereferencing * is needed. If the function was expecting a value of the type the iterator refers to, then you would need to dereference it first. In that case the compiler calls the overloaded operator *and returns the value.
That is the nature of overloaded operators -- they look like ordinary operators but ultimately are resolved to a function call defined by the creator of the class. It works the same as if you defined a matrix class that has plus and minus operators overloaded.
How it works does * means any other things to iterator or *itr act like normal pointer variable.
It depends what type stands behind iterator. It can be alias for a pointer:
using iterator = int *;
iterator itr;
*itr; // it is pointer dereferencing in this case.
Or it can be a user defined type:
struct iterator {
int &operator*();
};
iterator itr;
*itr; // it means itr.operator*() here
So without knowing what type iterator is it is quite impossible to say what * actually does here. But in reality you should not care as developers of the library should implement it the way it would not matter for you.
If I have the end iterator to a container, but I want to get a raw pointer to that is there a way to accomplish this?
Say I have a container: foo. I cannot for example do this: &*foo.end() because it yields the runtime error:
Vector iterator not dereferencable
I can do this but I was hoping for a cleaner way to get there: &*foo.begin() + foo.size().
EDIT:
This is not a question about how to convert an iterator to a pointer in general (obviously that's in the question), but how to specifically convert the end iterator to a pointer. The answers in the "duplicate" question actually suggest dereferencing the iterator. The end iterator cannot be dereferenced without seg-faulting.
The correct way to access the end of storage is:
v.data() + v.size()
This is because *v.begin() is invalid when v is empty.
The member function data is provided for all contiguous containers (vector, string and array).
From C++17 you will also be able to use the non-member functions:
data(v) + size(v)
This works on raw arrays as well.
In general? No.
And the fact that you're asking indicates that something is wrong with your overall design.
For vectors, arrays, strings? Sure… but why?
Just get a pointer to a valid element, and advance it:
std::vector<T> foo;
const T* ptr = foo.data() + foo.size();
As long as you don't dereference such a pointer (which is almost equivalent to dereferencing the iterator, as you did in your attempt) it is valid to obtain and hold such a pointer, because it points to the special one-past-the-end location.
Note that &foo[0] + foo.size() has undefined behaviour if the vector is empty, because &foo[0] is &*(foo.data() + 0) is &*foo.data(), and (just like in your attempt) *foo.data() is disallowed if there's nothing there. So we avoid all dereferencing and simply advance foo.data() itself.
Anyway, this only works for the case of vectors1, arrays and strings, though. Other containers do not guarantee (or can be reasonably expected to provide) storage contiguity; their end pointers could be almost anything, e.g. a "sentinel" null pointer, which is unlikely to be of any use to you.
That is why the iterator abstraction is there in the first place. Stick to it if you can, instead of delving into raw pointer usage.
1. Excepting std::vector<bool>.
I've been trying to understand c++ by going over some projects and i came across this:
vector<Circle>::iterator circleIt = mCircles.end();
..
mCurrentDragCircle = &(*circleIt);
Why would you dereference and then reference it again?
The *-operator is overloaded for the iterator class. It doesn't do a simple dereference. Instead, it returns a reference to the variable it's currently pointing at. Using the reference operator on this returns a pointer towards the variable.
Using mCurrentDragCircle = circleIt; would assign the iterator to your field.
circleIt is an iterator, and iterators overload operator* so that they look like pointers. Dereferencing an iterator gives a reference to the value; & turns that into a pointer to the value. So this is converting an iterator to a pointer.
Btw., dereferencing past-the-end, i.e. *v.end(), has undefined behavior. The proper way to do this is
v.data() + v.size()
in C++11, or
&v[0] + v.size()
in C++98. Both assume the vector is non-empty.
Because of how iterators works.
*circleIt
will return instance of Circle, e.g. you can do
Circle & c = *circleIt;
Than you take address of that circle and store it into a pointer
Circle * mCurrentDragCircle = & (*circleIt);
Hope this helps.
&* is a particularly pernicious idiom for extracting an underlying pointer. It's frequently used on objects that have an overloaded dereference operator *.
One such class of objects are iterators. The author of your class is attempting to get the address of the underlying datum for some reason. (Two pitfalls here, (i) *end() gives undefined behaviour and (ii) it appears that the author is storing the pointer value; blissfully unaware that modifications on that container could invalidate that value).
You can also see it used with smart pointers to circumvent reference counting.
My advice: avoid if at all possible.
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).
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.