If one creates a const reference to a temporary, its life is extended as if the reference where in the stack. It is a good feature of the language, although it is presented sometimes like an exception to other rules. https://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/
However this doesn't work when the const reference is part the member of a class. Is this an inconsistency of the language?
Example code:
int f(int a){return a + 5;}
int main(){
int const& b = f(2);
assert(b == 7); // ok, not a dangling reference
struct single{
int const& m_;
single(int const& m) : m_(m){}
};
single s{f(3)};
assert(s.m_ == 8); // fails, dangling reference
struct pair{
int const& m1_;
int const& m2_;
pair(int const& m1, int const& m2) : m1_(m1), m2_(m2){}
};
pair p{f(3), f(4)};
assert( p.m1_ == 8 ); // fails, dangling reference
}
Is there a workaround for this to work or at least behave more consistently?
I found this to be a limiting factor in a few contexts now. For example, List using with references, changes behavior when used as a member and https://stackoverflow.com/a/51878764/225186
EDIT1: In other answers to similar questions is mentioned that the problem is that the constructor takes a const&
where the rule doesn't apply.
However a perfect forward still fails.
In this case, either the inconsistency in the language is more evident or perfect forward is not as perfect.
struct single{
int const& m_;
template<class T>
single(T&& m) : m_(std::forward<T>(m)){}
};
EDIT2: Declaring single const& s{f(3)};
still doesn't help.
However "moving" the constness to the structure helps.
struct single{
int m_; // no const!
template<class T>
single(T&& m) : m_(std::forward<T>(m)){}
};
...
single const& s{f(3)}; // const ref with extended lifetime
So, perhaps it is good practice to transfer the constness to the whole struct.
I still think that reference members behave weirdly in the language. https://www.youtube.com/watch?v=uYDt1gCDxhM
EDIT3: As @Oliv mentions, the situation improves if one uses agregate initialization. However this is quite limiting.
struct single{
int const& m_;
};
...
single s{f(3)};
assert(s.m_ == 5);