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.
Related
I had some problems converting a std::list<MyType>::iterator to MyType*. I have an array of MyType and as I loop through it, I call some void doSomething(const MyType* thing). Eventually I do this:
std::list<MyType> types = ... something here ...;
for( std::list<MyType>::const_iterator it = types.begin(), end = types.end(); it != end; ++it ) {
doSomething(&*it);
}
My question is, whether I do or do not create a memory copy of the MyType by this operation:
&*it
Trying to simply pass the iterator as if it was pointer, or to cast the iterator to pointer raised compiler errors.
No, the sequence of * and & does not create a copy:
* applied to an iterator produces a reference
& applied to a reference produces the address of the original
Neither of these two steps requires copying of MyType's data.
Note: When the presence of an overloaded operator & is a possibility, it is safer to use std::address_of(*it) expression.
One of the requirements for an iterator is that it be derefernceable -- i.e. *it be supported. See http://en.cppreference.com/w/cpp/concept/Iterator. Whether *it returns a reference or a copy is not specified.
In theory, an implementation could return a copy when using *it.
In practice, most implementations return a reference when using *it. Hence, you most likely won't be seeing a copy being made when using &*it.
As long as the iterator is valid it is doing what your want. And no, it does not create a copy.
Based on how your code is written, you are creating a copy of the pointer, but the memory being pointed to by the pointer should not be copied.
Broken down, you take the iterator object (it), you look at the MyType object referenced by the iterator (*it), and then get the address of this object (&*it). The pointer is then copied into the function and used as you desire.
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>.
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).
I've been using some semi-iterators to tokenize a std::string, and I've run into a curious problem with operator[]. When constructing a new string from a position using char*, I've used something like the following:
t.begin = i;
t.end = i + 1;
t.contents = std::string(&arg.second[t.begin], &arg.second[t.end]);
where arg.second is a std::string. But, if i is the position of the last character, then arg.second[t.end] will throw a debugging assertion- even though taking a pointer of one-past-the-end is well defined behaviour and even common for primitive arrays, and since the constructor is being called using iterators I know that the end iterator will never be de-referenced. Doesn't it seem logical that arg.second[arg.second.size()] should be a valid expression, producing the equivalent of arg.second.end() as a char*?
You're not taking a pointer to one past the end, you're ACCESSING one past the end and then getting the address of that. Entirely different and while the the former is well defined and well formed, the latter is not either. I suggest using the iterator constructor, which is basically what you ARE using but do so with iterators instead of char*. See Alexandre's comment.
operator[](size_type pos) const doesn't return one-past-the-end is pos == size(); it returns charT(), which is a temporary. In the non-const version of operator[], the behavior is undefined.
21.3.4/1
const_reference operator[](size_type pos) const;
reference operator[](size_type pos);
1 Returns: If pos < size(), returns data()[pos]. Otherwise, if pos == size(), the const
version returns charT(). Otherwise, the behavior is undefined.
What is well-defined is creating an iterator one past the end. (Pointers might be iterators, too.) However, dereferencing such an iterator will yield Undefined Behavior.
Now, what you're doing is array subscription, and that is very different from forming iterators, because it returns a reference to the referred-to object (much akin to dereferencing an iterator). You are certainly not allowed to access an array one-past-the-end.
std::string is not an array. It is an object, whose interface loosely resembles an array (namely, provides operator[]). But that's when the similarity ends.
Even if we for a second assume that std::string is just a wrapper built on top of an ordinary array, then in order to obtain the one-past-the-end pointer for the stored sequence, you have to do something like &arg.second[0] + t.end, i.e. instead of going through the std::string interface first move into into the domain of ordinary pointers and use ordinary low-level pointer arithmetic.
However, even that assumption is not correct and doing something like &arg.second[0] + t.end is a recipe for disaster. std::string is not guaranteed to store its controlled sequence as an array. It is not guaranteed to be stored continuously, meaning that regardless of where your pointers point, you cannot assume that you'll be able to iterate from one to another by using pointer arithmetic.
If you want to use an std::string in some legacy pointer-based interface the only choice you have is to go through the std::string::c_str() method, which will generate a non-permanent array-based copy of the controlled sequence.
P.S. Note, BTW, that in the original C and C++ specifications it is illegal to use the &a[N] method to obtain the one-past-the-end pointer even for an ordinary built-in array. You always have to make sure that you are not using the [] operator with past-the-end index. The legal way to obtain the pointer has always been something like a + N or &a[0] + N, but not &a[N]. Recent changes legalized the &a[N] approach as well, but nevertheless originally it was not legal.
A string is not a primitive array, so I'd say the implementation is free to add some debug diagnostics if you are doing something dangerous like accessing elements outside its range. I would guess that a release build will probably work.
But...
For what you are trying to do, why not just use the basic_string( const basic_string& str, size_type index, size_type length ); constructor to create the sub strings?