c++11 - C++: rvalue references used in ternary operator seem to break existing code -
i'm porting 1 of projects, has been developed years using borland c++-builder 5 , 6, current embarcadero c++-builder xe 3 update 2. xe 3 supports of new c++11-things rvalue references of course of study new me, due former used old compilers. needed few modifications project compilable, during runtime i'm facing 1 problem seems result of new rvalue references , move semantics.
i have class field of type std::wstring storing path read 1 method using field in ternary operator following:
std::wstring retval = somecondition ? this->classfield : util::dosomething(somearg);
somecondition phone call std::wstring.empty() , util::dosomething returns std::wstring value, no reference or else involved, copied data.
with xe 3, after first time somecondition evaluated true, retval gets filled content of classfield, afterwards classfield's content empty. using debugger follow execution optimized assignment operator whith rvalue references:
#if _has_rvalue_references [...] _myt& operator=(_myt&& _right) { // assign moving _right homecoming (assign(_std forward<_myt>(_right))); } _myt& assign(_myt&& _right) { // assign moving _right [...]
what i've read rvalue references explain problem, found 2 comments explaining why classfield treated rvalue.
http://stackoverflow.com/a/8535301/2055163
http://stackoverflow.com/a/6957421
i can prepare line above 1 additional manual re-create of classfield:
std::wstring retval = somecondition ? std::wstring(this->classfield) : util::dosomething(somearg);
but doesn't solve problem need review each , every usage of ternary operator (where lvalues , rvalues mixed) in each project want port without help compiler, because it's runtime problem may or may not occur.
what don't understand if there's wrong or bad practice usage of ternary operator? there improve solutions observe cases? why should manually re-create objects trick optimizations? intended behavior , no problems in of codebase out there? how deal such problems?
i'm bit confused on how progress right , appreciate suggestions and/or explanations. thanks!
i tested next 2 cases worked:
http://ideone.com/mwxxk3
the first illustration looks similar case, expect no class instances used store global string. dummy2 filled , dummy keeps content.
std::wstring retval = somecondition ? this->classfield : dosomethingresult;
when alter line above remove rvalue saving result of util:... std::wstring before using ternary operator, works expected. retval has content , this->classfield keeps its, too.
what's conclusion now? :-/
looks compiler bug. relevant section of standard 5.16p6:
[if] sec , 3rd operands have same type; result of type. if operands have class type, result prvalue temporary of result type, copy-initialized either sec operand or 3rd operand depending on value of first operand.
if util::dosomething(somearg)
returned std::string&&
instead of value, we'd need section 5.16p3:
otherwise, if sec , 3rd operand have different types , either has (possibly cv-qualified) class type, or if both glvalues of same value category , same type except cv-qualification, effort made convert each of operands type of other. process determining whether operand look e1
of type t1
can converted match operand look e2
of type t2
deļ¬ned follows:
e2
lvalue: e1
can converted match e2
if e1
can implicitly converted type "lvalue reference t2
", subject constraint in conversion reference must bind straight lvalue. if e2
xvalue: e1
can converted match e2
if e1
can implicitly converted type "rvalue reference t2
", subject constraint reference must bind directly. if e2
rvalue or if neither of conversions above can done , @ to the lowest degree 1 of operands has (possibly cv-qualified) class type: if e1
, e2
have class type, , underlying class types same or 1 base of operations class of other: e1
can converted match e2
if class of t2
same type as, or base of operations class of, class of t1
, , cv-qualification of t2
same cv-qualification as, or greater cv-qualification than, cv-qualification of t1
. if conversion applied, e1
changed prvalue of type t2
copy-initializing temporary of type t2
e1
, using temporary converted operand. otherwise (i.e., if e1
or e2
has nonclass type, or if both have class types underlying classes not either same or 1 base of operations class of other): e1
can converted match e2
if e1
can implicitly converted type look e2
have if e2
converted prvalue (or type has, if e2
prvalue). the 4th bullet applies, re-create should made automatically, no changes needed source code.
in both cases, temporary re-create can moved safely when constructing retval
.
c++ c++11 ternary-operator move-semantics rvalue-reference
No comments:
Post a Comment