以下代码是否会调用未定义的行为?据我所知,我们应该总是使用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还是定义好的?
答案 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之后,您应该始终显式释放内存,否则会导致内存泄漏。