c++ - Temporary lifetime and perfect forwarding constructor -
c++ - Temporary lifetime and perfect forwarding constructor -
i having problem understanding why lifetime of temporaries bound const reference parameters cutting short when there perfect forwarding constructor around. first of, know temporaries bound reference parameters: lastly total expression:
a temporary bound reference parameter in function phone call (5.2.2) persists until completion of total look containing call
however found cases not true (or might misunderstand total look is). let's take simple example, first define object verbose constructors , destructors:
struct { a(int &&) { cout << "create a" << endl; } a(a&&) { cout << "move a" << endl; } ~a(){ cout << "kill a" << endl; } };
and object wrapper b, used reference collapsing:
template <class t> struct b { t value; b() : value() { cout << "new b" << endl; } b(const t &__a) : value(__a) { cout << "create b" << endl; } b(const b &p) = default; b(b && o) = default; ~b(){ cout << "kill b" << endl; }; };
we can utilize our wrapper capture references on temporaries , utilize them in function calls, so:
void foo(b<const a&> a){ cout << "using a" << endl; } int main(){ foo( {123} ); }
the programme above prints expect:
create create b using kill b kill
so far good. let's move b
, add together perfect forwarding constructor convertible types:
template <class t> struct b { /* ... */ template <class u, class = typename enable_if<is_convertible<u, t>::value>::type> b(u &&v) : value(std::forward<u>(v)) { cout << "new forwards initialized b" << endl; } };
compiling same code 1 time again gives:
create new forwards initialized b kill using kill b
note our a
object killed before used, bad! why did lifetime of temporary not extended total phone call of foo
in case? also, there no other phone call desctructor of a
, there no other instance of it.
i can see 2 possible explanations:
either types not think are: changing convertible move constructorb(t &&v)
instead of template <class u>b(u &&v)
solves problem. or {123}
not subexpression of foo( {123} )
. swapping {123}
a(123)
solves issue, makes me wonder if brace-initializers total expressions. could clarify going on here?
does mean adding forwarding constructor class break backward compatibility in cases, did b
?
you can find total code here, test case crashing references strings.
the type inferred u
in phone call b<a const&>::b(u&&)
int
, temporary can lifetime-extended phone call foo
in main
prvalue int
temporary initialized 123
.
the fellow member a const& value
bound temporary a
, a
created in mem-initializer-list of constructor b<a const&>::b(u&&)
lifetime extended duration of fellow member initialization [class.temporary]/5:
— temporary bound reference fellow member in constructor’s ctor-initializer (12.6.2) persists until constructor exits.
note mem-initializer-list part after colon in ctor-initializer:
template <class u, class = typename enable_if<is_convertible<u, t>::value>::type> b(u &&v) : value(std::forward<u>(v)) { ^--- ctor-initializer ^--- reference fellow member ^--- temporary
this why kill a
printed after new forwards initialized b
.
does mean adding forwarding constructor class break backward compatibility in cases, did b
?
yes. in case it's hard see why forwarding constructor necessary; it's unsafe have reference fellow member temporary bound to.
c++ c++11
Comments
Post a Comment