我认为它应该,因为它对正确性很重要。但是,我很惊讶地看到 Clang 的输出。考虑下面的代码:
#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";
}
我们定义了一个 move ctorS
来检查是否S(S&&)
被调用,如果没有,则应用 NRVO。
我们从 GCC 看到的结果是:
0x7ffc3ed7b5ac
0x7ffc3ed7b5ac
42
应用了 NRVO,它们采用相同的地址,这是预期的。
但是,Clang 的输出:
0x7fff908bbcc8
0x7fff908bbcf8
42
应用了 NRVO,但地址不同。
如果您想知道为什么拥有相同的地址很重要 - 这是因为某些对象可能会在构造时对其地址进行一些注册,并且如果对象被移动,则应该通知它(例如通过 move-ctor)。
应用了 NRVO 但具有不同的内存地址因此使其格式错误。这明显违反了合同 - 没有调用自定义移动/复制 ctor,编译器如何将 S 的数据“复制”到不同的地方?
这是 Clang 中的错误吗?
如果我们添加一个析构函数S
,例如
~S() {}
这一次,Clang 输出相同的地址。