C++ 不应该';NRVO保证本地命名变量和调用站点变量采用相同的地址吗?
我认为应该,因为这对正确性很重要。然而,我对Clang的输出感到惊讶。考虑下面的代码:C++ 不应该';NRVO保证本地命名变量和调用站点变量采用相同的地址吗?,c++,nrvo,C++,Nrvo,我认为应该,因为这对正确性很重要。然而,我对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}
#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";
}
应用了NRVO,并且它们采用了预期的相同地址
然而,克朗:
已应用NRVO,但地址不同
如果您想知道为什么拥有相同的地址很重要,这是因为某些对象可能会在构建时使用其地址进行一些注册,并且如果对象被移动,则应通知它(例如,通过移动ctor)
应用了NRVO,但具有不同的内存地址,因此使其格式不正确。
这显然违反了合同-没有调用自定义移动/复制ctor,编译器如何将s的数据“复制”到其他地方
这是叮当作响的虫子吗
如果我们将析构函数添加到
S
,例如
~S() {}
,Clang输出相同的地址。显然是Clang中的一个bug,它们应该是相同的,否则下面的内容将是错误的
struct S
{
int i;
int* ptr;
S(int i) : i(i) {
this->ptr = &this->i;
}
S(S&& s)
{
this->i = s.i;
this->ptr = &this->i;
std::cout << "S(S&&)\n";
}
S(S const&) = delete;
};
结构
{
int i;
int*ptr;
S(int i):i(i){
此->ptr=&此->i;
}
S(S&S)
{
这个->i=s.i;
此->ptr=&此->i;
std::cout@Still.用这种想法回答了这个问题,他们真的应该是电子邮件链的起点。这是Clang完全实现的安腾ABI规范中的一个错误。是的。只有当sizeof(S)好的,ABI传递规则将“NRVO vs.复制/移动”联系在一起时才会这样做对非平凡析构函数的行为…但是当已经做出了有利于复制/移动(re:Clang)的决定时,哪个ABI规则允许复制而不调用任何构造函数?在这种情况下,Clang使用了什么复制机制?ABI对此怎么说?
~S() {}
struct S
{
int i;
int* ptr;
S(int i) : i(i) {
this->ptr = &this->i;
}
S(S&& s)
{
this->i = s.i;
this->ptr = &this->i;
std::cout << "S(S&&)\n";
}
S(S const&) = delete;
};