大佬教程收集整理的这篇文章主要介绍了c – 是否会在堆上分配内存以支持临时对象与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引用的对象相同的存储位置,而不在堆栈或堆上进行任何额外的分配?
#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,请注明来意。