编译器控件如何帮助分配&在C ++中释放内存?

时间:2014-01-13 06:11:40

标签: c++ memory compiler-construction allocation

我在一本C ++书中读到malloc()& free()是liabrary函数,因此不受编译器的控制。

但是,如果您有一个运营商来执行动态存储分配的组合行为&初始化(new)和另一个操作员执行清理的组合行为&释放存储(delete),编译器仍然可以保证构造函数&将为所有对象调用析构函数。

所以,我想知道这是如何由编译器执行的? 任何示例或演示都将被评估。

提前致谢。

3 个答案:

答案 0 :(得分:4)

malloc function 返回一大块连续内存,就是这样。你如何键入和使用它(对你的对象)是你的问题。

new 运算符返回内存中分配的对象。虽然两者都返回一个指针,但最终你得到构造的对象,而不是C ++中的原始内存。在这里,重点从低级内存处理转移到类型安全的对象处理。这就是new不返回void*的原因。

另外,如果您注意到,在前一种情况下,C,它是一个执行分配的函数,即语言本身没有分配对象或内存的概念。虽然在C ++中new是一个运算符,因此该语言本身就能理解动态创建对象的含义。编译器实现了语言所要求的内容,因此可以在发现错误时标记错误。

一个例子是:

int *ptr = malloc(sizeof(char) * 4);

这里程序员假设一个大小为 4 的整数,虽然在他的平台上可能也是如此,但并非所有平台都是如此。另外,概念上charint是不同的类型,但 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;
}

类似的逻辑适用于删除。