Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

question for NRVO in if-branch

29 views
Skip to first unread message

anho...@gmail.com

unread,
Jul 17, 2020, 5:47:32 PM7/17/20
to
Hi Experts,

I have a question for following code:

string p(bool x)
{
if(x){
const string s = "1111111111111111111111111111111111111111111111111";
std::cout << "var address: " << &s << std::endl;
std::cout << "buf address: " << (void *)(s.data()) << std::endl;
return s; // expect NRVO but actually copy ctor?
}
else{
const string s = "2222222222222222222222222222222222222222222222222";
std::cout << "var address: " << &s << std::endl;
std::cout << "buf address: " << (void *)(s.data()) << std::endl;
return s; // expect NRVO but actually copy ctor?
}
}

int main()
{
{
std::cout << "call p(true), expect NRVO" << std::endl;
auto s = p(true);

std::cout << "var address: " << &s << std::endl;
std::cout << "buf address: " << (void *)(s.data()) << std::endl;
}

std::cout << "===============" << std::endl;

{
std::cout << "call p(false), expect NRVO" << std::endl;
auto s = p(false);

std::cout << "var address: " << &s << std::endl;
std::cout << "buf address: " << (void *)(s.data()) << std::endl;
}

return 0;
}


$ g++ main.cpp -std=c++17

output is:

call p(true), expect NRVO
var address: 0x7fffc084bd50
buf address: 0x7fffb9b97280
var address: 0x7fffc084bda0
buf address: 0x7fffb9b972c0
===============
call p(false), expect NRVO
var address: 0x7fffc084bd50
buf address: 0x7fffb9b972c0
var address: 0x7fffc084bda0
buf address: 0x7fffb9b97280


as you see, I expect it uses NRVO because when reach the string constructor, the compiler already sure the string it's constructing will get returned.

But the result is not, it uses copy constructor.

I searched many and the closest one is saying ``it's not guarenteed here for NRVO in the if-branch, even in c++17", but they didn't give reason.

So, WHY?
Thanks everyone!

Öö Tiib

unread,
Jul 17, 2020, 9:49:36 PM7/17/20
to
Copy elision is allowed but not required there. On general when there
are several local variables from what function returns then it can be
impossible to decide.

What verbiage you would propose for requiring copy elision there by
standard? Do not forget to take things like possible exceptions thrown
etc. into account.

As of WHY compiler implementer did not implement something that
is allowed but not required then maybe he had other things to
implement or had to go to bring kids from school or to go buy
milk or something. No one knows.

Move (that you apparently also check by observing addresses of
data()) is on any case not allowed as there can't be move
from const.

Ian Collins

unread,
Jul 17, 2020, 10:01:00 PM7/17/20
to
On 18/07/2020 13:49, Öö Tiib wrote:
> On Saturday, 18 July 2020 00:47:32 UTC+3, anho...@gmail.com wrote:
>> Hi Experts,
>>
>> I have a question for following code:
>>

<snip>
That's a good point regarding const, if it is removed gcc will, as
expected, move:

call p(true), expect NRVO
var address: 0x7ffd50656360
buf address: 0x5584106ba280
var address: 0x7ffd506563b0
buf address: 0x5584106ba280
===============
call p(false), expect NRVO
var address: 0x7ffd50656360
buf address: 0x5584106ba280
var address: 0x7ffd506563b0
buf address: 0x5584106ba280

Clang does apply cop[y elision, with the const:
p$ clang++ -m64 -std=c++17 x.cc && ./a.out

call p(true), expect NRVO
var address: 0x7fff4a401478
buf address: 0x2575280
var address: 0x7fff4a401478
buf address: 0x2575280
===============
call p(false), expect NRVO
var address: 0x7fff4a401448
buf address: 0x2575280
var address: 0x7fff4a401448
buf address: 0x2575280

--
Ian.


anho...@gmail.com

unread,
Jul 17, 2020, 11:33:37 PM7/17/20
to
在 2020年7月17日星期五 UTC-7下午7:01:00,Ian Collins写道:
thanks for point out clang can trigger NRVO here.
I tried online clang compiler and confirms it.

If there is no const, I expect it should use move ctor, no problem.
If the const is here, I would expect it uses copy ctor.

But check this one: http://cpp.sh/3s2ho

the buffer address is same...
Does this means it also calls move ctor even s is const-qualified?

anho...@gmail.com

unread,
Jul 17, 2020, 11:42:29 PM7/17/20
to
在 2020年7月17日星期五 UTC-7下午7:01:00,Ian Collins写道:
actually seems for this online compiler, if use container string, looks like the buf get moved:
http://cpp.sh/3s2ho

if I swith to test the vector, the buffer is different, like using copy:
http://cpp.sh/6kcsb

hmm, strange to me.

Paavo Helde

unread,
Jul 18, 2020, 2:44:42 AM7/18/20
to
18.07.2020 00:47 anho...@gmail.com kirjutas:

>
> $ g++ main.cpp -std=c++17
[...]
> as you see, I expect it uses NRVO
If you are studying how compiler optimizations work it might be useful
to switch on compiler optimizations (-O2 or -O3).

Some compilers might indeed do some optimizations even without such a
switch, and some optimizations (not NRVO) are indeed mandatory since
C++17. But anyway it seems pointless to study optimizations without
switching them on.


Bonita Montero

unread,
Jul 18, 2020, 2:57:48 AM7/18/20
to
Am 17.07.2020 um 23:47 schrieb anho...@gmail.com:
> Hi Experts,
> I have a question for following code:
> string p(bool x)
> {
> if(x){
> const string s = "1111111111111111111111111111111111111111111111111";
Don't make it const.
> std::cout << "var address: " << &s << std::endl;
> std::cout << "buf address: " << (void *)(s.data()) << std::endl;
> return s; // expect NRVO but actually copy ctor?
> }
> else{
> const string s = "2222222222222222222222222222222222222222222222222";
Don't make it const.

Alf P. Steinbach

unread,
Jul 18, 2020, 6:54:32 AM7/18/20
to
The missing key phrase here "in all cases".

One example small change of the code is like this:

auto foo( const bool x )
-> string
{
string s2 = "222";
if( x == fermats_conjecture_is_true() ) {
string s1 = "111";
return s1;
}
return s2;
}

Here also in theory the compiler knows in all cases, but

* Evaluating `fermats_conjecture_is_true()` at compile time can
be very expensive.
* Copy elision involves moving the declaration of s2.

More generally, copy elision can involve code transformations that have
to be proved yield the same abstract machine effect, and attempting such
a proof for every potential elision candidate would be costly.

So the standard /allows/ the optimization but does not /require/ it.

Put another way, if the standard /requires/ the optimization, then there
is a defect in the standard.


> But the result is not, it uses copy constructor.
>
> I searched many and the closest one is saying ``it's not guarenteed
> here for NRVO in the if-branch, even in c++17", but they didn't give
> reason.
>
> So, WHY? Thanks everyone!

See ^.

- Alf
0 new messages