C&C++   发布时间:2022-04-03  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了c – 是否会在堆上分配内存以支持临时对象与const引用的嵌套绑定?大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
虑以下代码,它以“嵌套”方式将临时对象绑定到const引用:

#include <iostream>

std::string foo()
{
    return "abc";
}

std::string goo()
{
    const std::string & a = foo();
    return a;
}

int main()
{
    // Is a temporary allocated on the heap to support this,even for a moment?
    const std::string & b = goo();
}

我一直试图理解编译器在内存存储方面必须做些什么才能支持这种“嵌套”结构.

我怀疑对于foo()的调用,内存分配很简单:当函数foo()退出时,std :: String的存储将在堆栈上分配.

但是,编译器必须做些什么来支持b引用的对象的存储?函数goo的堆栈必须展开并“替换为”b引用的堆栈上的对象,但是为了展开goo的堆栈,编译器是否需要在堆上暂时创建对象的副本(在将其复制回不同位置的堆栈之前)?

或者编译器是否可以完成此构造的要求而不在堆上分配任何存储,即使是暂时的?

或者甚至可以让编译器对b所引用的对象使用与a引用的对象相同的存储位置,而不在堆栈或堆上进行任何额外的分配?

@H_801_20@解决方法
下面是C标准允许编译器重建代码的示例.我正在使用完整的NRVO.注意使用placement new,这是一个中等模糊的C功能.你传递一个新的指针,它在那里而不是在免费商店中构造结果.

#include <iostream>

void __foo(void* __construct_std_String_at)
{
  new(__construct_std_String_at)std::string("abc");
}

void __goo(void* __construct_std_String_at)
{
  __foo(__construct_std_String_at);
}

int main()
{
  unsigned char __buff[sizeof(std::string)];
  // Is a temporary allocated on the heap to support this,even for a moment?
  __goo(&__buff[0]);
  const std::string & b = *reinterpret_cast<std::string*>(&__buff[0]);
  // ... more code here using b I assume
  // end of scope destructor:
  reinterpret_cast<std::string*>(&__buff[0])->~std::string();
}

如果我们在goo中阻止了NRVO,那么它看起来就像

#include <iostream>

void __foo(void* __construct_std_String_at)
{
  new(__construct_std_String_at)std::string("abc");
}

void __goo(void* __construct_std_String_at)
{
  unsigned char __buff[sizeof(std::string)];
  __foo(&__buff[0]);
  std::string & a = *reinterpret_cast<std::string*>(&__buff[0]);
  new(__construct_std_String_at)std::string(a);
  // end of scope destructor:
  reinterpret_cast<std::string*>(&__buff[0])->~std::string();
}

int main()
{
  unsigned char __buff[sizeof(std::string)];
  // Is a temporary allocated on the heap to support this,even for a moment?
  __goo(&__buff[0]);
  const std::string & b = *reinterpret_cast<std::string*>(&__buff[0]);
  // ... more code here using b I assume
  // end of scope destructor:
  reinterpret_cast<std::string*>(&__buff[0])->~std::string();
}

基本上,编译器知道引用的生命周期.因此,它可以创建存储变量的实际实例的“匿名变量”,然后创建对它的引用.

我还注意到,当你调用一个函数时,你有效地(隐式地)将一个指向缓冲区的指针传递给返回值所在的位置.因此被调用函数调用者的作用域中构造对象“就地”.

使用NRVO,被调用函数作用域中的命名变量实际上是在调用函数“返回值所在的位置”中构造的,这使得返回变得容易.没有它,你必须在本地做所有事情,然后在return语句中通过相应的placement new将你的返回值复制到指向你的返回值的隐式指针.

没有什么需要在堆(也就是免费商店)上完成,因为生命周期都很容易证明和堆栈排序.

具有预期签名的原始foo和goo必须仍然存在,因为它们具有外部链接,直到在发现没有人使用它们时可能被丢弃.

所有以__开头的变量和函数仅用于展示.编译器/执行环境不再需要具有命名变量,而不需要具有红血球名称. (理论上,因为__是保留的,在编译之前执行这样的转换传递的编译器可能是合法的,如果你实际使用了那些变量名并且编译失败,那将是你的错,而不是编译器的错,但是……那将是一个非常hackey编译器.;))

大佬总结

以上是大佬教程为你收集整理的c – 是否会在堆上分配内存以支持临时对象与const引用的嵌套绑定?全部内容,希望文章能够帮你解决c – 是否会在堆上分配内存以支持临时对象与const引用的嵌套绑定?所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。