我一直在阅读有关如何在C ++中分配内存的信息。
要提及的一些资源:
http://www.geeksforgeeks.org/memory-layout-of-c-program/
http://duartes.org/gustavo/blog/post/anatomy-of-a-program-in-memory
Object creation on the stack/heap?
Global memory management in C++ in stack or heap?
http://msdn.microsoft.com/en-us/library/vstudio/dd293645.aspx
Heap / Stack and multiple processes
Do different programs gets their memory from a common heap or from a separate heap?
http://computer.howstuffworks.com/c28.htm
我想根据我的阅读澄清几点:
根据http://www.geeksforgeeks.org/memory-layout-of-c-program/第4节“堆栈”,存储自动变量的堆栈,以及每次调用函数时保存的信息“
假设:
class myClass{
int a;
char b;
public:
myClass(int a,char b)
{
this->a = a;
this->b = b;
}
};
1)根据我所读到的,当我们编译这段代码时,二进制文件位于程序存储器中,并且还没有在堆栈上分配任何内容。正确的吗?
现在在我的主要:
int main()
{
myClass Ob(1,'c');
return 0;
}
2)现在,在堆栈上创建了一个大小为5字节(4字节(整数),1字节(字符) - 32位OS)的对象Ob,因为它是一个自动变量。正确吗?
3)当调用构造函数myClass(int a,char b)
时,临时变量(参数a,b)是否在构造函数的堆栈上创建,然后在创建对象Ob后销毁?就像我们通过按值传递参数来调用函数一样。
现在假设另一个班级
class pointerClass {
int a;
char* b;
public:
pointerClass(int size){
b= new char[size];
a=size;
}
};
现在主要:
int main()
{
pointerClass ptr(10) ; //Step 1
}
4)这是否意味着大小为8字节的ptr对象(int a(4字节),char * b(4字节,即这只是持有指向堆的地址)是在堆栈上创建的?还有10字节的内存(对应于新的char [10]在堆上分配)由char * b的内容指向?我是否正确?
5)当我们通过引用(例如fn (int *a,char* b)
或fn(int& a,char& b)
将参数传递给函数时,这意味着在堆栈上为指向实际对象的函数创建临时指针/引用在函数返回时被传递和销毁?或者更确切地说,传递实际对象而不是在函数的堆栈上创建和销毁临时指针/引用?
我昨天问过,但我对答案不满意: Constructor, Copy Constructor and Stack Creation : C++
6)当我们重载诸如fn(int a,char b)
fn(int& a,char& b)
之类的fn时,我们可以从main调用fn(A,B)
以下演员
static_cast<void(*)(int, char)>(fn)(a, c); //Calls fn(int a,char b)
static_cast<void(*)(int&, char&)>(fn)(a, c);//Calls fn(int& a.char& b)
到底发生了什么?什么是空(*)。
由于
答案 0 :(得分:6)
sizeof
即可获得尺寸。答案 1 :(得分:4)
void(*)(int,char)
是一个类型,特别是指向带有两个参数和int和char的void函数的指针。很明显,这个演员会强制编译器选择你想要的函数的版本,虽然这对我来说是可能的。当然必须添加强制性警告,即C ++中不需要上述任何内容,而是通常如何实现C ++。
答案 2 :(得分:3)
首先,我应该指出你所展示的图表是非常的 系统依赖。例如,Solaris下的操作 系统内存根本没有映射到用户地址空间。 最常见的映射只有三个映射段 用户内存,至少在程序的开头:代码 在底部(但不是绝对底部),因为 地址0通常不会被映射),它上面的数据段, 并且在顶部有一个堆叠段(长大),有一个大的 堆栈和数据之间未映射的内存空洞。
一旦动态启动,所有这些都会完全改变 加载。
没有。完成代码后(在更大的意义上) 编译),可执行文件在文件中,而不在内存中。该 程序在执行之前不会加载到内存中。 (在早期的Unix和嵌入式系统中曾经存在一些例外 系统,即使在今天。但对于像。这样的通用系统 Windows和现代Unix,这是真的。)
将在堆栈上创建变量。但它几乎会 由于对齐,肯定会大于5个字节 注意事项。 (八个字节是大多数32的最小值 位机。)在C ++中,对象创建是一个两步过程: 内存分配和调用构造函数。多数情况 实现,所有必要的内存 将分配函数中使用的所有对象 立即,在功能的顶部;在某些情况下,额外的 内存也将分配在每个变量的任一侧, 出于调试原因,内存将被初始化。 程序流时将调用该对象的构造函数 传递对象的定义。
是。调用构造函数就像调用一个
任何其他功能。同样,创建参数是一个两步过程;
在这种情况下,策略各不相同:有些实现会
在顶部分配任何参数所需的所有内存
该功能,其他人将根据需要分配它们
在初始化它们之前。而在简单的情况下
变量,如int
,大多数机器只有一条指令
这将允许在同一个中分配和初始化
指令。取决于参数的类型以及方式
它们被初始化,编译器甚至可能使用不同的
策略。
正确,或多或少。对于内置类型,如int
或
指针,唯一的“破坏”就是释放记忆,而且
取决于编译器,可能直到最后才会发生
调用函数。 (另一方面,如果你打电话
第二个功能,这个内存将被重用。所以该计划
行为完全“好像”记忆已立即释放。)
正确,或多或少。 (形式上,参考文献不是 “被摧毁”,因为它们不是物体。实际上,至少 当它们被用作函数参数时,底层代码 与指针完全相同。)
首先,你可以用 来完成结果
指向函数的指针上的static_cast
将其强制转换为
它的原始类型。其他任何东西都是未定义的行为。如果
使用{的结果将fn
定义为void fn( int a, char b )
static_cast<void (*) ( int&, char& )>( fn )
未定义
行为,将无法正常工作。这里究竟发生了什么
几乎任何东西,但它很有可能
程序崩溃。在这种情况下,void (*)
是部分
声明函数类型的指针; void (*)( int, char
)
,是要使用的类型:指针(*
)的名称(
( int, char )
- 因为括号是必要的
优先规则)返回void
。
编辑:
只是对第6点进行了修正。我错过了这个事实
两种类型的函数都被重载了。一个static_cast
可以
用于解决这样的函数重载:在这样的
例如,通常的规则不适用,因为没有类型
转换。 (是的,这非常令人困惑。)