I have the following code:
struct Foo {
int var1;
int var2;
friend std::ostream& operator<<(std::ostream& os, const Foo& s){
return os << "[Foo] " << s.var1 << "," << s.var2 ;
}
};
int main() {
Foo foo;
foo.var1 = 1;
foo.var2 = 2;
std::list<Foo> list;
list.push_back(foo);
Foo &foo2 = list.front();
foo2.var2 = 5;
std::cout << "foo (" << &foo << "): " << foo << std::endl;
std::cout << "foo2 (foo from list) (" << &list.front() << "): " << foo2 << std::endl;
}
I want both foo
and foo2
to reference the same object. So when I assign 5
to foo2.var2
, I would want to modify foo.var2
as well. Yet, as we can see in the following output this is not happening:
foo (0x7fffffffe140): [Foo] 1,2
foo2 (foo from list) (0x61ac30): [Foo] 1,5
What would be the correct way to do that?
When you use push_back
to insert elements into a list, push_back
creates a copy which is inserted into the list. A solution is to use a std::reference_wrapper
instead as the underlying type of the list, like
std::list<std::reference_wrapper<Foo>> lst;
and then push into it like
lst.push_back(foo);
Here is a super simple example that shows you how it works:
#include <functional>
#include <iostream>
#include <list>
int main()
{
int i = 42;
std::list<std::reference_wrapper<int>> lst;
lst.push_back(i); // we add a "reference" into the list
lst.front().get() = 10; // we update the list
std::cout << i; // the initial i was modified!
}
You need the reference_wrapper
since you cannot simply create a list of references, like std::list<Foo&>
. Alternatively, you can use pointers, but I find the reference_wrapper
approach more transparent.
In the simple example above note the need to use std::reference_wrapper::get()
to obtain the underlying reference, as the reference_wrapper
is on the left hand side of the assignment operator and hence won't be implicitly converted to int
via std::reference_wrapper::operator T&
.
Below is your full working code modified to use reference_wrapper
s: