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 constructor b(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

Popular posts from this blog

formatting - SAS SQL Datepart function returning odd values -

c++ - Apple Mach-O Linker Error(Duplicate Symbols For Architecture armv7) -

php - Yii 2: Unable to find a class into the extension 'yii2-admin' -