I am developing a memory critical application. I first generate a list, for example (C++11):
std::list<string> nodes({"Hello","Welcome", "Hi", "World"});
I need to now create a smaller list with the second and third elements of 'nodes.' Naively, I would do:
std::list<string> sub_nodes;
sub_nodes.push_back(*std::next(nodes.begin(),1));
sub_nodes.push_back(*std::next(nodes.begin(),2));
But this clearly allocates memory in the heap for sub_nodes
by allocating new memory.
*(sub_nodes.begin()) = "NotWelcome"; //changing first element
std::list<string>::iterator it;
for(it=nodes.begin();it!=nodes.end();++it) cout<<*it<<'\t';
cout<<'\n';
//Hello Welcome Hi World
for(it=sub_nodes.begin();it!=sub_nodes.end();++it)
cout<<*it<<'\t';
cout<<'\n';
//NotWelcome Hi
What I wish to accomplish is to have the elements of sub_nodes
occupy the same address of the elements of nodes
from which they were created. In other words, I want the changes made to elements of sub_nodes
reflected in those elements in nodes
and vice versa. In C linked lists, this would be straight forward since the list nodes are basically pointers. How would I accomplish the same in C++?
You can use std::reference_wrapper
, which works as a reference and is able to be stored in a container.
std::list<std::reference_wrapper<std::string>> sub_nodes; // #include <functional>
Note although std::reference_wrapper
has an implicit conversion operator to its value type, sometimes you still have to use its explicit get
method. For example, you have to use
(*sub_nodes.begin()).get() = "NotWelcome";
to change the referenced object.
The following is a full working example:
#include <iostream>
#include <functional>
#include <list>
#include <string>
int main()
{
std::list<std::string> nodes({"Hello","Welcome", "Hi", "World"});
std::list<std::reference_wrapper<std::string>> sub_nodes;
sub_nodes.push_back(*std::next(nodes.begin(), 1));
sub_nodes.push_back(*std::next(nodes.begin(), 2));
(*sub_nodes.begin()).get() = "NotWelcome";
for (auto it = nodes.begin(); it != nodes.end(); ++it) std::cout << *it << '\t';
std::cout << '\n';
// Hello NotWelcome Hi World
for (auto it = sub_nodes.begin(); it != sub_nodes.end(); ++it)
std::cout << (*it).get() << '\t';
std::cout << '\n';
// NotWelcome Hi
}