Reputation: 35438
Please consider the following code:
#include <iostream>
template <class T>
class value_wrapper
{
public:
value_wrapper(T& pv) : v(pv) { std::cout<< "CONS.REF:" << pv << " AT:" << (void*)this << std::endl; }
value_wrapper(T&& pv) : v(pv) { std::cout<< "CONS.UNIREF:" << pv << " AT:" << (void*)this << std::endl; }
virtual ~value_wrapper() { std::cout<< "DEST:" << v << " AT:" << (void*)this << std::endl; }
value_wrapper(const value_wrapper& ov) : v(ov.v) { std::cout<< "CONS.COPY.REF:" << v << " AT:" << (void*)this << std::endl; }
value_wrapper(value_wrapper&& ov) : v(ov.v) { std::cout<< "CONS.COPY.UNIREF:" << v << " AT:" << (void*)this << std::endl; }
value_wrapper<T>& operator = (value_wrapper<T>&& ov)
{
std::cout<< "ASSI.UNIREF: OF " << v << " AT:" << (void*)this << " TO:" << ov.v << " AT:" <<(void*)&ov << " ADR.VAL:" << (void*)(&ov.v)<< std::endl;
v = ov.v;
return *this;
}
private:
template <typename V> friend value_wrapper<V> operator - (const value_wrapper<V> v1, const V& v2);
T& v;
};
template<typename T>
value_wrapper<T> operator - (const value_wrapper<T> v1, const T& v2)
{
T f = v1.v - v2;
value_wrapper<T> res(f);
std::cout << "MINUS: RESULT:" << res.v << " AT:" << (void*)&res << " ADR.VAL:" << &res.v << std::endl;
return res;
}
template<typename X>
value_wrapper<X> _ (X& a)
{
return value_wrapper<X>(a);
}
int main()
{
int a = 5;
std::cout << "BEFOR:" << a<< std::endl;
_(a) = _(a) - 1;
std::cout << "AFTER:" << a<< std::endl;
return 0;
}
And their online presence:
(The bad one) http://cpp.sh/7yav
(The good one) http://coliru.stacked-crooked.com/a/ea7363eaba68a336
While the first one outputs:
BEFOR:5
CONS.REF:5 AT:0x761cebd52310
CONS.REF:4 AT:0x761cebd52320
MINUS: RESULT:4 AT:0x761cebd52320 ADR.VAL:0x761cebd522cc
CONS.REF:5 AT:0x761cebd52300
ASSI.UNIREF: OF 5 AT:0x761cebd52300 TO:0 AT:0x761cebd52320 ADR.VAL:0x761cebd522cc
DEST:0 AT:0x761cebd52300
DEST:27644 AT:0x761cebd52320
DEST:0 AT:0x761cebd52310
AFTER:0
and the second one outputs:
g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
BEFOR:5
CONS.REF:5 AT:0x7fffc51a5710
CONS.REF:4 AT:0x7fffc51a5720
MINUS: RESULT:4 AT:0x7fffc51a5720 ADR.VAL:0x7fffc51a56fc
CONS.REF:5 AT:0x7fffc51a5700
ASSI.UNIREF: OF 5 AT:0x7fffc51a5700 TO:4 AT:0x7fffc51a5720 ADR.VAL:0x7fffc51a56fc
DEST:4 AT:0x7fffc51a5700
DEST:4 AT:0x7fffc51a5720
DEST:4 AT:0x7fffc51a5710
AFTER:4
So, here comes the question:
what happened to the rvalue from the moment it had the correct value:
MINUS: RESULT:4 AT:0x761cebd52320 ADR.VAL:0x761cebd522cc
Till the correct value disappeared from the same address:
ASSI.UNIREF: OF 5 AT:0x761cebd52300 TO:0 AT:0x761cebd52320 ADR.VAL:0x761cebd522cc
It seems, that I use the same compiler (g++ (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4) as the one from cpp.sh because I get the same results...
Is this a compiler bug, or just my misunderstanding of how a standard rvalue should work?
EDIT:
I Expected the line:
ASSI.UNIREF: OF 5 AT:0x761cebd52300 TO:0 AT:0x761cebd52320 ADR.VAL:0x761cebd522cc
to be:
ASSI.UNIREF: OF 5 AT:0x761cebd52300 TO:4 AT:0x761cebd52320 ADR.VAL:0x761cebd522cc
ie: the value 0 to be 4 just as in the other printout, becaue that has to be the correct value, not 0.
Upvotes: 0
Views: 106
Reputation: 98436
I think you have an undefined behaviour here:
template<typename T>
value_wrapper<T> operator - (const value_wrapper<T> v1, const T& v2)
{
T f = v1.v - v2;
value_wrapper<T> res(f);
return res;
}
See? You are returning a value_wrapper<T>
that encapsulates a reference to T
, and that reference refers to f
. Buf f
is a local variable, so you return a dangling reference, and that is UB.
Upvotes: 6