在C ++中使用malloc后的行为

时间:2010-09-18 04:22:05

标签: c++ malloc

以下代码是否会调用未定义的行为?据我所知,我们应该总是使用new来动态创建用户定义的对象,因为除了malloc之外,new也会调用构造函数。

#include <cstdio>
#include <cstdlib>

struct om
{
    int a;
    void fun()
    {
        a=10;b=10;
    }
    private : int b;

} s1; // structure(om) variable... 


typedef struct om node;

int main()
{
node *s2=(node *)malloc(sizeof(node));
s1.fun();
printf("%d",s2->a);
return 0;
}

以上代码打印0.这意味着s2->a会自动初始化为0? 所以我想知道程序Implmentation定义的行为,Undefined还是定义好的?

5 个答案:

答案 0 :(得分:4)

malloc无法保证初始化它分配的内存 - 如果你想用0填充内存,那么使用calloc

答案 1 :(得分:3)

  

上面的代码打印0.这意味着s2-> a自动初始化为0?

没有。 malloc没有这样的保证。很可能在你的简单例子中发生的事情是,malloc碰巧使用了一个新的内存区域,恰好在那时它只有零。因为程序非常简单,所以每次都可能重复这种行为。但是在一个更复杂的程序中,内存被重用,你不会总是看到零。

  

据我所知,我们应该总是使用new来动态创建用户定义的对象,因为除了malloc之外,new也会调用构造函数。

是。 malloc不会调用构造函数。 new。在C ++中编写代码时,强烈建议总是更喜欢new而不是malloc(甚至对于基本类型,而不仅仅是用户定义的类型)。

  

以下代码是否会调用未定义的行为?

我不是语言律师,但我会试一试......

我相信可以说这是一个明确定义的行为,这种未初始化的变量具有未定义的值。因此,无论s2->a最终具有什么价值,它都遵循C ++标准。

答案 2 :(得分:1)

您正在解释一段原始内存(这是std::malloc()返回的内容)作为对象(强制转换(node*)malloc(...)),然后访问其上的成员(s2->a)。实际上,只要类型只包含内置类型的成员而没有指针,你就可以逃脱它,但从技术上来说,它会调用未定义的行为。
调用未定义的行为很糟糕,因为它允许程序执行任何操作。它可能会使您的程序崩溃,无声地产生错误的结果,格式化您的HD,刻录您的CPU,让您怀孕,或者它可能按您期望的方式工作。它可能现在表现一种方式,但不同于新的编译器版本,操作系统升级,在另一个平台上,在客户的站点,当您的老板在周日观看时,或根据月相。

构造函数是将原始内存转换为有效对象的原因。在堆栈,全局对象或使用new表达式创建对象时,将自动运行构造函数。您可以使用 placement new 分隔内存分配和构造。这样做,您可以获取std::malloc()分配的内存并在其上调用构造函数。但是你为什么要这样做呢?除了优化(以及作为C ++ std lib中类型使用的机制)之外,很少需要使用placement new。

为什么您的问题仍标记为C++?当然,C ++编译器会使用一些明显的修复来编译它,但除了C ++样式包含C std lib头之外,没有关于它的C ++,它充满了C-isms。 你确定要编程C ++吗?或者你不熟悉C?如果是这样,坚持使用C可能比在C ++中编写C更好。在C语言中,很多被认为是好的东西在C ++中被认为是不好的。

答案 3 :(得分:1)

行为未定义。 malloc不会调用构造函数来初始化内存。这就是为什么它是用C ++分配内存的最快方法

答案 4 :(得分:0)

  

很可能在你的简单例子中发生的事情是,malloc碰巧使用了新的内存区域,恰好在那时只有零。

其实没有,这是编译器的细节。另外,请考虑这样的程序代码:

#include <stdio.h>

int i;

int main() {
  while (i<10) {
    printf("Hello\n");
    i++;
  }
  return 0;
}

此程序的行为也是编译器细节。但通常会以这样的方式生成程序二进制文件,即变量值设置为0.但由于不能保证,所以在程序代码中使用变量之前,应始终初始化变量。

您的代码也是如此。使用malloc,您可以获得变量的内存片段,但不要初始化。因此,您可以使用此变量获得意外行为,因此您应该使用构造函数初始化它。

使用构造函数可以保证对象的至少某些字段是根据需要设置的,但是对于malloc,你对字段的实际值一无所知。

另请注意reference。很明显,malloc没有初始化任何东西。此外,在调用malloc之后,您应该始终显式释放内存,否则会导致内存泄漏。