What is the difference between these two parameters in C++? - c++

I am new to C++ and currently am learning about templates and iterators.
I saw some code implementing custom iterators and I'm curious to know what the difference between these two iterator parameters is:
iterator & operator=(iterator i) { ... i.someVar }
bool operator==(const iterator & i) { ... i.someVar }
They implement the = and == operators for the particular iterator. Assuming the iterator class has a member variable 'someVar', why is one operator implemented using "iterator i" and another with "iterator & i"? Is there any difference between the two "i.someVar" expressions?
I googled a little and found this question
Address of array - difference between having an ampersand and no ampersand
to which the answer was "the array is converted to a pointer and its value is the address of the first thing in the array." I'm not sure this is related, but it seems like the only valid explanation I could find.
Thank you!

operator= takes its argument by value (a.k.a. by copy). operator == takes its argument by const reference (a.k.a. by address, albeit with a guarantee that the object will not be modified).
An iterator may be/contain a pointer into an array but it is not itself an array.
The ampersand (&) has different contextual meanings. Used in an expression, it behaves as an operator. Used in a declaration such as iterator & i, it forms part of the type iterator & and indicates that i is a reference, as opposed to an object.
For more discussion (with pictures!), see Pass by Reference / Value in C++ and What's the difference between passing by reference vs. passing by value? (this one is language agnostic).

the assignment operator = takes the iterator i as value, which means a copy of the original iterator is made and passed to the function so any changes applied to the iterator i inside the operator method won't affect the original.
the comparison operator == takes a constant reference, which denotes that the original object can't/shouldn't be changed in the method. This makes sense since a comparison operator usually only compares objects without changing them. The reference allows to pass a reference to the original iterator which lives outside the method. This means that the actual object won't be copied which is usually faster.

First, you don't have an address of an array here.
There's no semantic difference, unless you try to make a local change to the local variable i: iterator i will allow a local change, while const iterator & i will not.
Many people are used to writing const type & var for function parameters because passing by reference can be faster than by value, especially if type is big and expensive to copy, but in your case, an iterator should be small and cheap to copy, so there's no gain from avoiding copying. (Actually, having a local copy can enhance locality of reference and help optimization, so I would just pass small values by value (by copying).)

Related

range based for loop with an auto reference to a pointer

With regard to the following code I would like to have some clarification. We have an array of pointers to a class. Next we loop over the array using a range based loop. For this range based loop auto& is used. But next when we use the element a we can use the arrow operator to call a function.
This code is compiled using C++ 11.
// Definition of an array of pointers to some class.
some_class* array[10];
// The array of pointers is set.
// Loop over the array.
for(auto& a : array)
{
// Call some function using the arrow operator.
a->some_func();
}
Is my understanding correct that auto& a is a reference to a pointer? Is this not a bit over kill. Would using auto a not create a copy of the pointer and take up the same amount of memory?
Your code compiles fine.
Nevertheless, there is not really a point using a reference here, if you don't like to change it.
Best practise here is
Use const auto &T if the content shall not be changed. The reference is important, if the type T of auto is large. Otherwise you will copy the object.
Use auto & T if you like to change the content of the container you are iterating.
Is my understanding correct that auto& a is a reference to a pointer?
Yes that's correct
Would using auto a not create a copy of the pointer and take up the same amount of memory
Think of references as an alias for the variable, that is, think of it as a different name.
as for this -> not create a copy of the pointer`
A pointer is very light weight and copying a pointer is relatively cheap (that's how views are implemented, pointers to sequences). If the object underline the container you are iterating is a fundamental type or a pointer to some type, auto is enough. In cases where the underline object of a container is a heavy weight object, then auto& is a better alternative (and ofc you can add const qualifier if you don't want to modify it).

What in the world is T*& return type

I have been looking at vector implementations and stumbled upon a line that confuses me as a naive C++ learner.
What is T*& return type?
Is this merely a reference to a pointer?
Why would this be useful then?
link to code: https://github.com/questor/eastl/blob/56beffd7184d4d1b3deb6929f1a1cdbb4fd794fd/vector.h#L146
T*& internalCapacityPtr() EASTL_NOEXCEPT { return mCapacityAllocator.first(); }
It's a reference-to-a-pointer to a value of type T which is passed as a template argument, or rather:
There exists an instance of VectorBase<T> where T is specified by the program, T could be int, string or anything.
The T value exists as an item inside the vector.
A pointer to the item can be created: T* pointer = &this->itemValues[123]
You can then create a reference to this pointer: https://msdn.microsoft.com/en-us/library/1sf8shae.aspx?f=255&MSPPError=-2147217396
Correct
If you need to use a value "indirectly" then references-to-pointers are cheaper to use than pointer-to-pointers as the compiler/CPU doesn't need to perform a double-indirection.
http://c-faq.com/decl/spiral.anderson.html
This would be a reference to a pointer of type T. References to pointers can be a bit tricky but are used a lot with smart pointers when using a reference saves an increment to the reference counter.
Types in C++ should be read from right to left. Following this, it becomes a: Reference to a pointer of T. So your assumption is correct.
References to pointers are very useful, this is often used as an output argument or an in-out argument. Let's consider a specific case of std::swap
template <typename T>
void swap(T*& lhs, T*& rhs) {
T *tmp = rhs;
rhs = lhs;
lhs = tmp;
}
As with every type, it can be used as return value. In the state library, you can find this return type for std::vector<int *>::operator[], allowing v[0] = nullptr.
On the projects that I've worked on, I haven't seen much usages of this kind of getters that allow changing the internals. However, it does allow you to write a single method for reading and writing the value of the member.
In my opinion, I would call it a code smell as it makes it harder to understand which callers do actual modifications.
The story is off course different when returning a const reference to a member, as that might prevent copies. Though preventing the copy of a pointer doesn't add value.

Does &*x operation create a copy?

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.

Evaluation of (de)reference operators

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 fa­vou­rite 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).

Any ideas why QHash and QMap return const T instead of const T&?

Unlike std::map and std::hash_map, corresponding versions in Qt do not bother to return a reference. Isn't it quite inefficient, if I build a hash for quite bulky class?
EDIT
especially since there is a separate method value(), which could then return it by value.
const subscript operators of STL containers can return a reference-to-const because they flat out deny calls to it with indexes that do not exist in the container. Behaviour in this case is undefined. Consequently, as a wise design choice, std::map doesn't even provide a const subscript operator overload.
QMap tries to be a bit more accommodating, provides a const subscript operator overload as syntactic sugar, runs into the problem with non-existing keys, again tries to be more accomodating, and returns a default-constructed value instead.
If you wanted to keep STL's return-by-const-reference convention, you'd need to allocate a static value and return a reference to that. That, however, would be quite at odds with the reentrancy guarantees that QMap provides, so the only option is to return by value. The const there is just sugar coating to prevent some stupid mistakes like constmap["foo"]++ from compiling.
That said, returning by reference is not always the most efficient way. If you return a fundamental type, or, with more aggressive optimisation, when sizeof(T)<=sizeof(void*), return-by-value often makes the compiler return the result in a register directly instead of indirectly (address to result in register) or—heaven forbid—on the stack.
The other reason (besides premature pessimisation) to prefer pass-by-const-reference, slicing, doesn't apply here, since both std::map and QMap are value-based, and therefore homogeneous. For a heterogeneous container, you'd need to hold pointers, and pointers are fundamental types (except smart ones, of course).
That all said, I almost never use the const subscript operator in Qt. Yes, it has nicer syntax than find()+*it, but invariably, you'll end up with count()/contains() calls right in front of the const subscript operator, which means you're doing the binary search twice. And then you won't notice the miniscule differences in return value performance anyway :)
For value() const, though, I agree that it should return reference-to-const, defaulting to the reference-to-default-value being passed in as second argument, but I guess the Qt developers felt that was too much magic.
The documentation for QMap and QHash specifically say to avoid operator[] for lookup due to the reason Martin B stated.
If you want a const reference, use const_iterator find ( const Key & key ) const where you can then use any of:
const Key & key () const
const T & value () const
const T & operator* () const
const T * operator-> () const
Actually, some of the methods do return a reference... for example, the non-const version of operator[] returns a T &.
However, the const version of operator[] returns a const T. Why? As "unwind" has already noted, the reason has to do with what happens when the key does not exist in the map. In the non-const operator[], we can add the key to the map, then return a reference to the newly added entry. However, the const operator[] can't do this because it can't modify the map. So what should it return a reference to? The solution is to make the const operator[] return const T, and then return a default-constructed T in the case where the key is not present in the map.
Weird, yes.
Perhaps this is because of the desired semantics, where doing e.g. value() on an unspecified key, returns a default-constructed value of the proper type. That's not possible using references, at least not as cleanly.
Also, things like name return value optimization can lessen the performance impact of this design.