为什么拿一个临时非法的地址?

Pra*_*rav 14 c++ temporary rvalue lvalue memory-address

我知道下面写的代码是非法的

void doSomething(std::string *s){}
int main()
{
     doSomething(&std::string("Hello World"));
     return 0;
}
Run Code Online (Sandbox Code Playgroud)

原因是我们不允许获取临时对象的地址.但我的问题是为什么?

让我们考虑以下代码

class empty{};
int main()
{
      empty x = empty(); //most compilers would elide the temporary
      return 0;
}
Run Code Online (Sandbox Code Playgroud)

公认的答案在这里提到

"通常编译器会将临时和副本构造为两个对象,它们位于内存的完全相同的位置,并避免复制."

根据声明,可以得出结论,临时存在于某个内存位置(因此可能已经采用了它),编译器决定通过在临时存在的同一位置创建就地对象来消除临时对象. .

这是否与临时地址不能采取的事实相矛盾?

我还想知道如何实现返回值优化.有人可以提供与RVO实施相关的链接或文章吗?

Jam*_*lis 13

&std::string("Hello World")
Run Code Online (Sandbox Code Playgroud)

这个问题不是std::string("Hello World")产生临时对象.问题是表达式std::string("Hello World")是一个引用临时对象的右值表达式.

您不能获取右值的地址,因为并非所有的右值都有地址(并非所有的右值都是对象).考虑以下:

42
Run Code Online (Sandbox Code Playgroud)

这是一个整数文字,它是主要表达式和右值.它不是一个对象,它(可能)没有地址. &42是荒谬的.

是的,右值可以引用一个对象,就像你的第一个例子中的情况一样.问题是并非所有的右值都引用了对象.

  • @Potatoswatter:`42`不是一个对象,它是一个值(并且类型为`int`).如果它绑定到const引用(即`const int&x = 42;`),则使用值"42"构造临时对象,并将引用绑定到该临时对象.(FWIW,我下意识地使用术语"rvalue"而不是"临时",忘记了引用已被绑定的临时对象仍然是一个临时对象;我将添加一个关于该...的注释.) (2认同)

cur*_*guy 6

答案很长:

[...]可以得出结论,临时存在于某些记忆位置

根据定义:

  • "temporary"代表:临时对象
  • 对象占据存储区域
  • 所有对象都有一个地址

因此,不需要非常精细的证据来证明临时具有地址.这是定义.

OTOH,您不只是获取地址,而是使用内置地址运算符.内置地址运算符的规范说你必须有一个左值:

  • &std::string()是形成不良的,因为std::string()是一个右值.在运行时,对此表达式的此求值将创建一个临时对象作为副作用,并且该表达式将生成一个引用所创建对象的右值.
  • &(std::string() = "Hello World")形成良好,因为std::string() = "Hello World"是一个左值.根据定义,左值是指对象.这个左值引用的对象是完全相同的临时对象

简短回答:

这是规则.它不需要某些人正在编造的(不正确,不健全)理由.