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?
Advantages of the List in C++ A linked list is a dynamic data structure that can expand and shrink in size at runtime by allocating and deallocating memory. As a result, there is no need to specify the linked list's initial size.
std::list. std::list is a container that supports constant time insertion and removal of elements from anywhere in the container. Fast random access is not supported. It is usually implemented as a doubly-linked list.
An std::reference_wrapper is a copyable and assignable object that emulates a reference. Contrary to its name, it does not wrap a reference. It works by encapsulating a pointer (T*) and by implicitly converting to a reference (T&).
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!
}
Live on Coliru
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:
http://coliru.stacked-crooked.com/a/fb1fd67996d6e5e9
Your std::list<Foo>
contains actual Foo
objects. When you call list.push_back(foo)
, it makes a copy of foo
. You are then declaring foo2
to reference that copied object, not the original object. That is why foo
is not updated when the members of foo2
are changed.
Try using pointers instead:
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 << "foo from list (" << foo2 << "): " << *foo2 << std::endl;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With