tags:

views:

132

answers:

5

Does the following code invoke undefined behaviour? As far as I know we should always use new to create user defined objects dynamically because new in addition to malloc calls the constructor too.

#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;
}

The above code prints 0. That means s2->a is automatically initialized to 0? So I want to know is the behaviour of the program Implmentation defined, Undefined or Well defined?

+4  A: 

malloc isn't guaranteed to initialize the memory it allocates - if you want the memory to be filled with 0's then use calloc.

Will A
Better still, since this claims to be C++, use `new node();`. Or add a default constructor and use `new node;` - that will correctly initialise `s1` as well as `s2`. Also, remember to delete `s2`, or assign it to a smart pointer.
Mike Seymour
+3  A: 

The above code prints 0. That means s2->a is automatically initialized to 0?

No. malloc makes no such guarantee. Most likely what is happening in your simple example is that malloc happens to use a fresh area of memory that happens to have only zeroes in it at that moment. Because the program is so simple, it may repeat this behavior every time. But in a more complex program where memory gets reused, you would not always see zeroes.

As far as I know we should always use new to create user defined objects dynamically because new in addition to malloc calls the constructor too.

Yes. malloc does not call constructors. new does. When writing code in C++ it is strongly advisable to always prefer new instead of malloc (and even for primitive types, not just user defined ones).

Does the following code invoke undefined behaviour?

I'm not a language lawyer, but I'll give this a shot...

I believe it could be said that it's a well defined behavior that such uninitialized variables have undefined values. So no matter what value s2->a ends up having, it is following the C++ standard.

TheUndeadFish
I think it's undefined. Firstly, `s1.a` could contain a trap value, in which case using it as an `int` is undefined behavior. Of course in most implementations, there's no trap values for `int`, so if you like it is implementation-defined whether it is undefined. Secondly, `om` is non-POD, so there is no guarantee that the compiler doesn't do some special magic on construction. Again, for this particular struct a typical implementation doesn't do anything special, but according to the standard, even calling a non-virtual member function or accessing a data member requires construction.
Steve Jessop
The behaviour is undefined, because the program tries to print the value of an uninitialised variable (`s2->a`).
Bart van Ingen Schenau
+1  A: 

You are interpreting a piece of raw memory (which is what std::malloc() returns) as an object (the cast (node*)malloc(...)) and then accessing a member on it (s2->a). In practice you might get away with it as long as the type only contains members of built-in types and no pointers, but technically that's invoking undefined behavior.
Invoking undefined behavior is bad, because it allows your program to do anything. It might crash your program, silently produce wrong results, format your HD, burn your CPU, make your pregnant, or it might work the way you expected it to. It might behave one way now, but differently with a new compiler version, an OS upgrade, on another platform, at a customer's site, when your boss watches, on Sundays, or depending on the moon phase.

A constructor is what turns raw memory into a valid object. Constructors are run automatically when you create objects on the stack, global objects, or using a new expression. You can separate memory allocation and construction by using placement new. Doing so, you could take memory allocated by std::malloc() and invoke a constructor on it. But why would you want to do this? Except for optimizations (and as a mechanism used by types in the C++ std lib), placement new is rarely ever needed.

Why was your question tagged C++ anyway? Of course, a C++ compiler would compile it with a few obvious fixes, but except for the C++-style includes of C std lib headers, there's nothing C++ about it, and it's full of C-isms.
Are you sure you want to program C++? Or aren't you more comfortable with C? If so, it might be better to stick with C than writing C in C++. Much of what's considered good in C is considered bad in C++.

sbi
A: 

Most likely what is happening in your simple example is that malloc happens to use a fresh area of memory that happens to have only zeroes in it at that moment.

Actually no, that's compiler specifics. Also, consider such piece of program code:

#include <stdio.h>

int i;

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

The behaviour of this program is also compiler specifics. But usually a program binary is generated in such a way, that the variable value is set to 0. But since it's not guaranteed, you should always initialize your variables before using them in program code.

The same is true for your code. With malloc you get a memory fragment for your variable, but you don't initialize. Therefore you can get unexpected behaviour using this variable, so you should initialise it with a constructor.

With a constructor you get a guarantee that at least some fields of the object are set as required, but with malloc you know nothing about the actual values of the fields.

Also watch this reference. It is said clearly that malloc does not initialize anything. Also, you should always free memory explicitly after calling malloc, otherwise you will get memory leaks.

SPIRiT_1984
+1  A: 

Behaviour is undefined. malloc doesn't call the construvtor ot initialize memory. And that's why it's the fastest method to allocate memory in C++

kizzx2