The following code run fine but, for what I understand, it shouldn't
#include <iostream>
#include <vector>
struct Data
{
explicit Data():value(1){}
int value;
};
struct Foo
{
explicit Foo(Data& data):data_(data){}
inline void print() const
{
std::cout<<data_.value<<std::endl;
}
Data& data_;
};
void addEntry(std::vector<Foo>& vec)
{
Data data;
Foo foo(data);
vec.push_back(foo);
}
int main()
{
std::vector<Foo> vec;
addEntry(vec);
vec[0].print();
}
The function addEnty
create an instance of Data
called data
. Then creates an instance of Foo
, called foo
, which stores a reference to data
. This istance is then copyed inside the vector vec
. Therefore, when the function end, vec[0]
should contain a dangling reference since data
is destroyed. Am I right? So I would expect to obtain some garbage calling the method print()
. Is it only by chance that I obtain the right value 1 or am I missing something?
To make it correct, I would move data in order to avoid the dangling reference. So I would modify the constructor with
explicit Foo(Data&& data):data_(data){}
and the function with
Foo foo(std::move(data));
In this way foo
, and consequently its copy inside vec[0]
, contains the instance data
instead of a reference to it. Am I right? Is it the correct solution? In this way, Foo::data_
needs to be of type Data
or of type Data&
?
Yes Foo will hold a dangling reference. Foo class should hold Data not Data& or Data&&.
#include <iostream>
#include <vector>
struct Data
{
explicit Data():value(1){}
int value;
};
struct Foo
{
// this is needed if you want to pass lvalue
Foo(const Data& data):data_(data)
{}
// for rvalue
Foo(Data&& data):data_(std::move(data))
{}
void print() const
{
std::cout<<data_.value<<std::endl;
}
Data data_;
};
void addEntry(std::vector<Foo>& vec)
{
vec.emplace_back(Foo(Data()));
// or
Data data;
// do somth with data
vec.emplace_back(Foo(std::move(data)));
// or
Data data;
// do somth with data
Foo foo {std::move(data)};
// do somth with foo, but
// do not use data here!!!
vec.push_back(std::move(foo));
}
int main()
{
std::vector<Foo> vec;
addEntry(vec);
vec[0].print();
}