Shouldn't NRVO guarantee the local named variable and the call-site variable to take the same address?

Viewed 290

I think it should, because it's important for correctness. However, I'm surprised to see Clang's output. Consider the code below:

#include <iostream>

struct S
{
    int i;

    S(int i) : i(i) {}

    S(S&&)
    {
        std::cout << "S(S&&)\n";
    }

    S(S const&) = delete;
};

S f()
{
    S s{42};
    std::cout << &s << "\n";
    return s;
}

int main()
{
    S s{f()};
    std::cout << &s << "\n";
    std::cout << s.i << "\n";
}

We defined a move ctor for S to check if S(S&&) is called, if not, NRVO is applied.

The result we see from GCC is:

0x7ffc3ed7b5ac
0x7ffc3ed7b5ac
42

NRVO is applied and they take the same address, which is expected.

However, Clang's output:

0x7fff908bbcc8
0x7fff908bbcf8
42

NRVO is applied but the addresses differ.

In case you wonder why having the same address is important - it's because some object may do some registration with its address at construction, and if the object is moved, it should be notified (e.g. via move-ctor).

Having NRVO applied but with different memory address thus makes it ill-formed. It's a clear violation of the contract - no custom move/copy ctor is called, how could the compiler "copy" the data of S to a different place?

Is this a bug in Clang?


If we add a destructor to S, e.g.

~S() {}

This time, Clang outputs the same address.

1 Answers
Related