why use references for mutable variables in c++ - c++

I'm new to c++. I came across some code and got confused
vector<int> vec{3,1,4,1,5};
vector<int> &vecRef = vec;
auto vecCopy = vecRef; // makes copy of vec
auto &vecRef2 = vecRef; // reference
I read about the usage of reference types in c++ and I understand why it's useful for immutable types. But for mutable types like vectors, what's the difference between vector vecCopy = vec and vector& vecRef = rec? Aren't they both alias to vec?

But for mutable types like vectors, what's the difference between
vector vecCopy = vec and vector& vecRef = rec? Aren't they both alias
to vec?
No. One is a copy of the entire vector. The other is a reference to the same.
Your example code is contrived. I can't think of any reasons why you would do this:
vector<int> vec{3,1,4,1,5};
vector<int> &vecRef = vec;
You pass variables by reference all the time. But I can't imagine a reason why I'd make a reference to a local variable like this, other than to illustrate an example of references as opposed to copies.
So: vecCopy is a whole DIFFERENT vector with its own contents. At the end of your code, it's identical in contents to vec, but after that, you can add to one or the other and they begin to diverge. vecRef is a reference to the exact same data. If you think of them as (under the hood) pointers, they point to the same object.

Difference between references and values.
One of the features of C++ is that it distinguishes between references and values. A lot of other languages don't do this. Let's say you have a vector:
std::vector<int> v1 = {1, 2, 3};
Creating a deep copy of this vector is really simple:
auto copy_of_v1 = v1;
We can prove it by changing copy_of_v1:
std::cout << (v1 == copy_of_v1) << '\n'; // Prints 1, for true
copy_of_v1[1] = 20; // copy_of_v1 == {1, 20, 3} now
std::cout << (v1 == copy_of_v1) << '\n'; // Prints 0, for false
Use cases for references.
References have three big use cases:
- Avoiding a copy by storing/using a reference
- Getting additional information out of a function (by passing it a reference, and letting it modify the reference)
- Writing data structures / container classes
We've seen the first case already, so let's look at the other two.
Using references to write functions that modify their input. Let's say you wanted to add the ability to append elements to vectors using +=. An operator is a function, so if it's going to modify the vector, it needs to have a reference to it:
// We take a reference to the vector, and return the same reference
template<class T>
std::vector<T>& operator +=(std::vector<T>& vect, T const& thing) {
vect.push_back(thing);
return vect;
}
This allows us to append elements to the vector just like it was a string:
int main() {
std::vector<int> a;
((a += 1) += 2) += 3; // Appends 1, then 2, then 3
for(int i : a) {
std::cout << i << '\n';
}
}
If we didn't take the vector by reference, the function wouldn't be able to change it. This means that we wouldn't be able to append anything.
Using references to write containers.
References make it easy to write mutable containers in C++. When we want to provide access to something in the container, we just return a reference to it. This provides direct access to elements, even primitives.
template<class T>
class MyArray {
std::unique_ptr<T[]> array;
size_t count;
public:
T* data() {
return array.get();
}
T const* data() {
return array.get();
}
MyArray() = default; // Default constructor
MyArray(size_t count) // Constructs array with given size
: array(new T[count])
, count(count) {}
MyArray(MyArray const& m) // Copy constructor
: MyArray(count) {
std::copy_n(m.data(), count, data();
}
MyArray(MyArray&&) = default;// Move constructor
// By returning a reference, we can access elements directly
T& operator[](size_t index) {
return array[index];
}
};
Now, when using MyArray, we can directly change and modify elements, even if they're primitives:
MyArray<int> m(10); // Create with 10 elements
m[0] = 1; // Modify elements directly
m[0]++; // Use things like ++ directly

Using references in c++ is the same as just using the name of the object itself. Therefore, you might consider a reference an alias.
vector<int> vec = {1, 2, 3};
vector<int>& vecRef = vec;
cout << vec.size() << '\n'; // Prints '3'
cout << vecRef.size() << '\n'; // Also prints '3'
It's worth noting that nobody really uses references to simply have another name for an existing object.
They are primarily used instead of pointers to pass objects without copying them.

C++ uses value semantics by default. Objects are values unless you specifically declare them to be references. So:
auto vecCopy = vecRef;
will create a value object called vecCopy which will contain a deep copy of vec since vecRef is an alias for vec. In Python, this would roughly translate to:
import copy
vec = [3, 1, 4, 1, 5]
vecCopy = copy.deepcopy(vec)
Note that it only "roughly" translates to that. How the copy is performed depends on the type of the object. For built-in types (like int and char for example,) it's a straightforward copy of the data they contain. For class types, it invokes either the copy constructor, or the copy assignment operator (in your example code, it's the copy constructor.) So it's up to these special member functions to actually perform the copy. The default copy constructor and assignment operators will copy each class member, which in turn might invoke that member's copy ctor or assignment operator if it has one, etc, etc, until everything has been copied.
Value semantics in C++ allow for certain code generation optimizations by the compiler that would be difficult to perform when using reference semantics. Obviously if you copy large objects around, the performance benefit of values will get nullified by the performance cost of copying data. In these cases, you would use references. And obviously you need to use references if you need to modify the passed object rather than a copy of it.
In general, value semantics are preferred unless there is a reason to use a reference. For example, a function should take parameters by value, unless the passed argument needs to be modified, or it's too big.
Also, using references can increase the risk of running into undefined behavior (pointers incur the same risks.) You can have dangling references for example (a reference that refers to a destroyed object, for example.) But you can't have dangling values.
References can also decrease your ability to reason about what is going on in the program because objects can get modified through references by non-local code.
In any event, it's a rather big subject. Things start to become more clear as you use the language and gain more experience with it. If there's a very general rule of thumb to take away from all this: use values unless there's a reason not to (mostly object size, requiring mutability of a passed function argument, or with runtime polymorphic classes since those require to be accessed through a reference or pointer when that access needs to be polymorphic.)
You can also find beginner articles and talks about the subject. Here's one to get you started:
https://www.youtube.com/watch?v=PkyD1iv3ATU

Related

C++ class with container of pointers to internal data members: copying/assignment

Suppose I have a class Widget with a container data member d_members, and another container data member d_special_members containing pointers to distinguished elements of d_members. The special members are determined in the constructor:
#include <vector>
struct Widget
{
std::vector<int> d_members;
std::vector<int*> d_special_members;
Widget(std::vector<int> members) : d_members(members)
{
for (auto& member : d_members)
if (member % 2 == 0)
d_special_members.push_back(&member);
}
};
What is the best way to implement the copy constructor and operator=() for such a class?
The d_special_members in the copy should point to the copy of d_members.
Is it necessary to repeat the work that was done in the constructor? I hope this can be avoided.
I would probably like to use the copy-and-swap idiom.
I guess one could use indices instead of pointers, but in my actual use case d_members has a type like std::vector< std::pair<int, int> > (and d_special_members is still just std::vector<int*>, so it refers to elements of pairs), so this would not be very convenient.
Only the existing contents of d_members (as given at construction time) are modified by the class; there is never any reallocation (which would invalidate the pointers).
It should be possible to construct Widget objects with d_members of arbitrary size at runtime.
Note that the default assignment/copy just copies the pointers:
#include <iostream>
using namespace std;
int main()
{
Widget w1({ 1, 2, 3, 4, 5 });
cout << "First special member of w1: " << *w1.d_special_members[0] << "\n";
Widget w2 = w1;
*w2.d_special_members[0] = 3;
cout << "First special member of w1: " << *w1.d_special_members[0] << "\n";
}
yields
First special member of w1: 2
First special member of w1: 3
What you are asking for is an easy way to maintain associations as data is moved to new memory locations. Pointers are far from ideal for this, as you have discovered. What you should be looking for is something relative, like a pointer-to-member. That doesn't quite apply in this case, so I would go with the closest alternative I see: store indices into your sub-structures. So store an index into the vector and a flag indicating the first or second element of the pair (and so on, if your structure gets even more complex).
The other alternative I see is to traverse the data in the old object to figure out which element a given special pointer points to -- essentially computing the indices on the fly -- then find the corresponding element in the new object and take its address. (Maybe you could use a calculation to speed this up, but I'm not sure that would be portable.) If there is a lot of lookup and not much copying, this might be better for overall performance. However, I would rather maintain the code that stores indices.
The best way is to use indices. Honestly. It makes moves and copies just work; this is a very useful property because it's so easy to get silently wrong behavior with hand written copies when you add members. A private member function that converts an index into a reference/pointer does not seem very onerous.
That said, there may still be similar situations where indices aren't such a good option. If you, for example have a unordered_map instead of a vector, you could of course still store the keys rather than pointers to the values, but then you are going through an expensive hash.
If you really insist on using pointers rather that indices, I'd probably do this:
struct Widget
{
std::vector<int> d_members;
std::vector<int*> d_special_members;
Widget(std::vector<int> members) : d_members(members)
{
for (auto& member : d_members)
if (member % 2 == 0)
d_special_members.push_back(&member);
}
Widget(const Widget& other)
: d_members(other.d_members)
, d_special_members(new_special(other))
{}
Widget& operator=(const Widget& other) {
d_members = other.d_members;
d_special_members = new_special(other);
}
private:
vector<int*> new_special(const Widget& other) {
std::vector<int*> v;
v.reserve(other.d_special_members.size());
std::size_t special_index = 0;
for (std::size_t i = 0; i != d_members.size(); ++i) {
if (&other.d_members[i] == other.d_special_members[special_index]) {
v.push_back(&d_members[i});
++special_index;
}
}
return v;
}
};
My implementation runs in linear time and uses no extra space, but exploits the fact (based on your sample code) that there are no repeats in the pointers, and that the pointers are ordered the same as the original data.
I avoid copy and swap because it's not necessary to avoid code duplication and there just isn't any reason for it. It's a possible performance hit to get strong exception safety, that's all. However, writing a generic CAS that gives you strong exception safety with any correctly implemented class is trivial. Class writers should usually not use copy and swap for the assignment operator (there are, no doubt, exceptions).
This work for me for vector of pairs, though it's terribly ugly and I would never use it in real code:
std::vector<std::pair<int, int>> d_members;
std::vector<int*> d_special_members;
Widget(const Widget& other) : d_members(other.d_members) {
d_special_members.reserve(other.d_special_members.size());
for (const auto p : other.d_special_members) {
ptrdiff_t diff = (char*)p - (char*)(&other.d_members[0]);
d_special_members.push_back((int*)((char*)(&d_members[0]) + diff));
}
}
For sake of brevity I used only C-like type cast, reinterpret_cast would be better. I am not sure whether this solution does not result in undefined behavior, in fact I guess it does, but I dare to say that most compilers will generate a working program.
I think using indexes instead of pointers is just perfect. You don't need any custom copy code then.
For convenience you may want to define a member function converting the index to actual pointer you want. Then your members can be of arbitrary complexity.
private:
int* getSpecialMemberPointerFromIndex(int specialIndex)
{
return &d_member[specialIndex];
}

Standard Practice for Creating a "Vector of References" Using Only the Standard Libraries

I would like to create an object, put the object into a vector, and still be able to modify the same object by accessing only the vector. However, I understand that when an object is push_back() to a vector, the object is actually copied into the vector. As a result, accessing the object in the vector will merely access a similar, but different object.
I have a beginner's knowledge in C, so I know that I can create a pointer to the object, and make a vector of pointers. e.g. vector<Object *>. However, it seems as if pointers are discouraged in C++, and references are preferred. Yet, I cannot make a vector of references.
I wish to use only the standard libraries, so boost is off limits to me.
I heard of smart pointers. However, it appears as if there are multiple types of smart pointers. Would it not be overkill for this purpose? If smart pointers are indeed the answer, then how do I determine which one to use?
So my question is: What is the standard practice for creating a vector of references/pointers to objects?
In other words, would like the below (pseudo-)code to work.
#include <iostream>
#include <cstdlib>
#include <vector>
using namespace std;
class Object
{
public:
int field;
};
vector<Object> addToVector(Object &o)
{
vector<Object> v;
v.push_back(o);
v[0].field = 3; // I want this to set o.field to 3.
return v;
}
int main()
{
Object one;
one.field = 1;
cout << one.field << endl; // 1 as expected
Object &refone = one;
refone.field = 2;
cout << one.field << endl; // 2 as expected
vector<Object> v = addToVector(one);
cout << v[0].field << endl; // 3 as expected
cout << one.field << endl; // I want to get 3 here as well, as opposed to 2.
return 0;
}
I would like to create an object, put the object into a vector, and still be able to modify the same object by accessing only the vector. However, I understand that when an object is push_back() to a vector, the object is actually copied into the vector. As a result, accessing the object in the vector will merely access a similar, but different object.
I'm almost certain that this is not what you want or "should" want. Forgive me that direct opening of my answer, but unless you have a very good reason to do this, you probably don't want to do it.
For that - a vector with references - to work you must guarantee that the referenced objects won't get moved nor destructed while you hold references to them. If you have them in a vector, make sure that vector isn't resized. If you have them on the stack like in your example, then don't let the vector of references or a copy of it leave that stack frame. If you want to store them in some container, use a std::list (it's iterators - pointers basically - don't get invalidated when inserting or removing elements).
You already noticed that you cannot have a vector of "real" references. The reason therefore is that references aren't assignable. Consider following code:
int a = 42;
int b = 21;
int & x = a; // initialisation only way to bind to something
int & y = b;
x = y;
b = 0;
After that, the value you obtain from x will be 21, because the assignment didn't change the reference (to be bound to b) but the referenced object, a. But a std::vector explicitly requires this.
You could now set out and write an wrapper around a pointer like ...
template<typename T>
struct my_ref {
T * target;
// don't let one construct a my_ref without valid object to reference to
my_ref(T & t) : target(&t) {}
// implicit conversion into an real reference
operator T &(void) {
return *target;
}
// default assignment works as expected with pointers
my_ref & operator=(my_ref const &) = default;
// a moved from reference doesn't make sense, it would be invalid
my_ref & operator=(my_ref &&) = delete;
my_ref(my_ref &&) = delete;
// ...
};
... but this is pretty pointless since std::reference_wrapper already provides exactly that:
int main (int, char**) {
int object = 21; // half of the answer
vector<reference_wrapper<int>> v;
v.push_back(object);
v[0].get() = 42; // assignment needs explicit conversion of lhs to a real reference
cout << "the answer is " << object << endl;
return 0;
}
(Example live here)
Now one could argue why using a wrapper around a pointer like std::reference_wrapper when one could also directly use a pointer. IMO a pointer, having the ability to be nullptr, changes the semantics of the code: When you have a raw pointer, it could be invalid. Sure, you can just assume that it's not, or put it somewhere in comments, but in the end you then rely on something that's not guaranteed by the code (and this behaviour normally leads to bugs).
If an element of your vector could "reference" an object or be invalid, then still raw pointers aren't the first choice (for me): When you use an element from your vector which is valid, then the object referenced by it is actually referenced from multiple places on your code; it's shared. The "main" reference to the object then should be a std::shared_ptr and the elements of your vector std::weak_ptrs. You can then (thread safe) acquire a valid "reference" (a shared pointer) when you need to and drop it when done:
auto object = make_shared<int>(42);
vector<weak_ptr<int>> v;
v.push_back (object);
// ... somewhere later, potentially on a different thread
if (auto ref = v[0].lock()) {
// noone "steals" the object now while it's used here
}
// let them do what they want with the object, we're done with it ...
Finally, please take my answer with a grain of salt, much of it is based on my opinion (and experience) and might not count as "standard practice".

are C++ structs fully copied or just referenced when assigned with '='?

If structs are fully copied, then the first loop is more expensive than the second one, because it is performing an additional copy for each element of v.
vector<MyStruct> v;
for (int i = 0; i < v.size(); ++i) {
MyStruct s = v[i];
doSomething(s);
}
for (int i = 0; i < v.size(); ++i) {
doSomething(v[i]);
}
Suppose I want to write efficient code (as in loop 2) but at the same time I want to name the MyStruct elements that I draw from v (as in loop 1). Can I do that?
Structs (and all variables for that matter) are indeed fully copied when you use =. Overloading the = operator and the copy constructor can give you more control over what happens, but there is no way you can use these to change the behavior from copying to referencing. You can work around this by creating a reference like this:
for (int i = 0; i < v.size(); ++i) {
MyStruct& s = v[i]; //& creates reference; no copying performed
doSomething(s);
}
Note that the struct will still be fully copied when you pass it to the function, unless the argument is declared as a reference. This is a common pattern when taking structs as arguments. For instance,
void doSomething(structType x);
Will generally perform poorer than
void doSomething(const structType& x);
If sizeof structType is greater than sizeof structType*. The const is used to prevent the function from modifying the argument, imitating pass-by-value behavior.
In your first example, the object will be copied over and you will have to deal with the cost of the overhead of the copy.
If you don't want the cost of the over head, but still want to have a local object then you could use a reference.
for (int i = 0; i < v.size(); ++i) {
MyStruct& s = v[i];
doSomething(s);
}
You can use references or pointers to avoid copying and having a name to relate to.
vector<MyStruct> v;
for (int i = 0; i < v.size(); ++i) {
MyStruct& s = v[i];
doSomething(s);
}
However since you use a vector for your container, using iterators might be a good idea. doSomething should take argument by const ref though otherwise, you'll still copy to pass argument to it.
vector<MyStruct> v;
for (vector<MyStruct>::iterator it = v.begin(); it != v.end(); ++it) {
doSomething(*it);
}
In your examples, you are creating copies. However not all uses of operator '=' will result in a copy. C++11 allows for 'move construction' or 'move assignment' in which case you aren't actually copying the data; instead, you're just (hopefully) making a high-speed move from one structure to another. (Naturally, what it ACTUALLY does is entirely dependent upon how the move constructor or move assignment operator is implemented, but that's the intent.)
For example:
std::vector<int> foo(); // returns a long vector
std::vector<int> myVector = std::move(foo());
Will cause a MOVE construction, which hopefully just performs a very efficient re-pointing of the memory in the new myVector object, meaning that you don't have to copy the huge amount of data.
Don't forget, however, about the return-value optimization, as well. This was just a trivial example. RVO is actually superior to move semantics when it can be used. RVO allows the compiler to simply avoid any copying or moving at all when an object is returned, instead just using it directly on the stack where it was returned (see http://en.wikipedia.org/wiki/Return_value_optimization). No constructor is called at all.
Copied*. Unless you overload the assignment operator. Also, Structs and Classes in C++ are the same in this respect, their copy behaviour does not differ as it does in c#.
If you want to dive deep into C++ you can also look up the move operator, but it is generally best to ignore that for beginners.
C++ does not have garbage collection, and gives more control over memory management. If you want behaviour similar to c# references, you can use pointers. If you use pointers, you should use them with smart pointers (What is a smart pointer and when should I use one?).
* Keep in mind, if the struct stores a pointer, the pointer in a copied struct will point to the same location. If the object in that location is changed, both structs' pointers will see the changed object.
P.S: I assume you come from a c# background based on the vocabulary in your question.

Returning an STL vector from a function - copy cost

When you return an stl vector from a function:
vector<int> getLargeArray() { ... }
Is the return going to be an expensive copy operation? I remember reading somewhere that vector assignment being fast -- should I require the caller to pass a reference instead?
void getLargeArray( vector<int>& vec ) { ... }
Assuming your function constructs and returns new data, you should return by value, and try to make sure that the function itself has one return point that returns a variable of type vector<int>, or at worst several return points that all return the same variable.
That ensures that you'll get the named return value optimization on any credible compiler, which eliminates one of the potential copies (the one from the value in the function, to the return value). There are other ways to get a return value optimization, but it's not wholly predictable so the simple rule plays safe.
Next, you want to eliminate the potential copy from the return value to whatever the caller does with it. It's the caller's problem to solve, not the callee's, and there are basically three ways to do this:
Use the call to the function as the initializer for a vector<int>, in which case again any credible C++ compiler will elide the copy.
Use C++11, where vector has move semantics.
In C++03, use "swaptimization".
That is, in C++03 don't write
vector<int> v;
// use v for some stuff
// ...
// now I want fresh data in v:
v = getLargeArray();
Instead:
getLargeArray().swap(v);
This avoids the copy assignment that's required (must not be elided[*]) for v = getLargeArray(). It's not needed in C++11, where there's a cheap move assignment instead of the expensive copy assignment, but of course it still works.
Another thing to consider is whether you actually want vector as part of your interface. You could instead perhaps write a function template that takes an output iterator, and writes the data to that output iterator. Callers who want the data in a vector can then pass in the result of std::back_inserter, and so can callers who want the data in a deque or list. Callers who know the size of the data in advance could even pass just a vector iterator (suitably resize()d first) or a raw pointer to a large enough array, to avoid the overhead of back_insert_iterator. There are non-template ways of doing the same thing, but they'll most likely incur a call overhead one way or another. If you're worried about the cost of copying an int per element, then you're worried about the cost of a function call per element.
If your function doesn't construct and return new data, but rather it returns the current contents of some existing vector<int> and isn't allowed to change the original, then you can't avoid at least one copy when you return by value. So if the performance of that is a proven problem, then you need to look at some API other than return-by-value. For example you might supply a pair of iterators that can be used to traverse the internal data, a function to look up a value in the vector by index, or even (if the performance problem is so serious as to warrant exposing your internals), a reference to the vector. Obviously in all those cases you change the meaning of the function -- now instead of giving the caller "their own data" it provides a view of someone else's data, which might change.
[*] of course the "as if" rule still applies, and one can imagine a C++ implementation that's smart enough to realise that since this is a vector of a trivially copyable type (int), and since you haven't taken any pointers to any elements (I assume), then it can swap instead and the result is "as if" it copied. But I wouldn't count on it.
You are very likely to get return value optimization, depending on the structure of the function body. In C++11 you could also benefit from move semantics.
Returning by value certainly has cleaner semantics, and I would see it as the preferred option, unless profiling proves it to be costly. There is a good related article here.
Here is a small example with a verbose dummy class, compiled with no optimization or C++11 support, using an old-ish version of GCC (4.3.4):
#include <vector>
#include <iostream>
struct Foo
{
Foo() { std::cout << "Foo()\n"; }
Foo(const Foo&) { std::cout << "Foo copy\n"; }
Foo& operator=(const Foo&) {
std::cout << "Foo assignment\n";
return *this;
}
};
std::vector<Foo> makeFoos()
{
std::vector<Foo> tmp;
tmp.push_back(Foo());
std::cout << "returning\n";
return tmp;
}
int main()
{
std::vector<Foo> foos = makeFoos();
}
The result on my platform is that all copying happens before the function return. If I compile with C++11 support, then the push_back results in a move copy rather than a C++03 copy construction.

Why Can't I store references in a `std::map` in C++?

I understand that references are not pointers, but an alias to an object. However, I still don't understand what exactly this means to me as a programmer, i.e. what are references under the hood?
I think the best way to understand this would be to understand why it is I can't store a reference in a map.
I know I need to stop thinking of references as syntactic suger over pointers, just not sure how to :/
They way I understand it, references are implemented as pointers under the hood. The reason why you can't store them in a map is purely semantic; you have to initialize a reference when it's created and you can't change it afterward anymore. This doesn't mesh with the way a map works.
You should think of a reference as a 'const pointer to a non-const object':
MyObject& ~~ MyObject * const
Furthermore, a reference can only be built as an alias of something which exists (which is not necessary for a pointer, though advisable apart from NULL). This does not guarantee that the object will stay around (and indeed you might have a core when accessing an object through a reference if it is no more), consider this code:
// Falsifying a reference
MyObject& firstProblem = *((MyObject*)0);
firstProblem.do(); // undefined behavior
// Referencing something that exists no more
MyObject* anObject = new MyObject;
MyObject& secondProblem = *anObject;
delete anObject;
secondProblem.do(); // undefined behavior
Now, there are two requirements for a STL container:
T must be default constructible (a reference is not)
T must be assignable (you cannot reset a reference, though you can assign to its referee)
So, in STL containers, you have to use proxys or pointers.
Now, using pointers might prove problematic for memory handling, so you may have to:
use smart pointers (boost::shared_ptr for example)
use a specialized container: Boost Pointer Container Library
DO NOT use auto_ptr, there is a problem with assignment since it modifies the right hand operand.
Hope it helps :)
The important difference apart from the syntactic sugar is that references cannot be changed to refer to another object than the one they were initialized with. This is why they cannot be stored in maps or other containers, because containers need to be able to modify the element type they contain.
As an illustration of this:
A anObject, anotherObject;
A *pointerToA=&anObject;
A &referenceToA=anObject;
// We can change pointerToA so that it points to a different object
pointerToA=&anotherObject;
// But it is not possible to change what referenceToA points to.
// The following code might look as if it does this... but in fact,
// it assigns anotherObject to whatever referenceToA is referring to.
referenceToA=anotherObject;
// Has the same effect as
// anObject=anotherObject;
actually you can use references in a map. i don't recommend this for big projects as it might cause weird compilation errors but:
map<int, int&> no_prob;
int refered = 666;
no_prob.insert(std::pair<int, int&>(0, refered)); // works
no_prob[5] = 777; //wont compile!!!
//builds default for 5 then assings which is a problem
std::cout << no_prob[0] << std::endl; //still a problem
std::cout << no_prob.at(0) << std::endl; //works!!
so you can use map but it will be difficult to guaranty it will be used correctly, but i used this for small codes (usually competitive) codes
A container that stores a reference has to initialize all its elements when constructed and therefore is less useful.
struct container
{
string& s_; // string reference
};
int main()
{
string s { "hello" };
//container {}; // error - object has an uninitialized reference member
container c { s }; // Ok
c.s_ = "bye";
cout << s; // prints bye
}
Also, once initialized, the storage for the container elements cannot be changed. s_ will always refer to the storage of s above.
This post explains how pointers are implemented under the hood - http://www.codeproject.com/KB/cpp/References_in_c__.aspx, which also supports sebastians answer.