我在一本C ++书中读到malloc()
& free()
是liabrary函数,因此不受编译器的控制。
但是,如果您有一个运营商来执行动态存储分配的组合行为&初始化(new
)和另一个操作员执行清理的组合行为&释放存储(delete
),编译器仍然可以保证构造函数&将为所有对象调用析构函数。
所以,我想知道这是如何由编译器执行的? 任何示例或演示都将被评估。
提前致谢。
答案 0 :(得分:4)
malloc
function 返回一大块连续内存,就是这样。你如何键入和使用它(对你的对象)是你的问题。
new
运算符返回内存中分配的对象。虽然两者都返回一个指针,但最终你得到构造的对象,而不是C ++中的原始内存。在这里,重点从低级内存处理转移到类型安全的对象处理。这就是new
不返回void*
的原因。
另外,如果您注意到,在前一种情况下,C,它是一个执行分配的函数,即语言本身没有分配对象或内存的概念。虽然在C ++中new
是一个运算符,因此该语言本身就能理解动态创建对象的含义。编译器实现了语言所要求的内容,因此可以在发现错误时标记错误。
一个例子是:
int *ptr = malloc(sizeof(char) * 4);
这里程序员假设一个大小为 4 的整数,虽然在他的平台上可能也是如此,但并非所有平台都是如此。另外,概念上char
和int
是不同的类型,但 C 编译器会忽略类型不匹配。它只需调用malloc
函数并将其返回的地址分配给ptr
。它的域名在那里结束,程序员可以使用(或滥用?)分配的内存。这不是编译器的错误或弱点,因为语言标准没有赋予编译器更多的权力来强制执行更多。
在C ++中
int *ptr = new char[4];
会被标记为错误;正确的方法是int *ptr = new int;
类型匹配。 C ++更加严格,通过在错误常见的地方允许较小的自由,从而导致更清晰的代码。类型安全可以说是C ++语言最大的安全特性。由于同样的原因,类型转换具有丑陋的语法:它们显示设计的弱点。使用更严格的语言,编译器能够对开发人员施加更多限制(因为人类更容易出错,在大多数情况下这很好用)。
答案 1 :(得分:2)
编译器并不真正直接“帮助”分配和释放内存;你的代码必须明确地这样做。当线程离开作用域(析构函数)时,C ++语言提供了代码的确定性执行。反过来,它通常用于释放堆分配的内存。
答案 2 :(得分:0)
new和delete是c ++中的关键词。
C ++编译器将为您生成隐藏代码,以处理内存分配/释放内容。
例如,
struct Test() { }
Test *a = new Test();
编译器可能会做这样的事情(以下是伪代码)
Test *a = (Test *)malloc(sizeof(Test));
if (a == nullptr) { throw std::bad_alloc; }
try
{
a.Test(); //call constructor
}
catch (...)
{
//constructor exception, free the memory first, then re-throw
free(a);
throw;
}
如果是数组,事情会更复杂,
struct Test() { }
Test *a = new Test[10];
编译器可能会这样做,
Test *a = (Test *)malloc(sizeof(Test) * 10);
if (a == nullptr) { throw std::bad_alloc; }
int i;
try
{
for (i = 0; i < 10, i++)
a[i].Test(); //call constructor
}
catch (...)
{
//call destructor for all constructed objects
for (int j = 0; j < i; j++)
a[j].~Test();
free(a);
throw;
}
类似的逻辑适用于删除。