malloc vs new for POD types

M

Method Man

Say I want to allocate a 10 element integer array. Here is the old C method:

int* arr = malloc(10 * sizeof (*arr));

Here is the C++ method:

int arr[] = new int[10];

Is there any difference between the two methods? What about when
deallocating the memory? It seems to me that, in this case, 'free(arr)'
would be faster than 'delete[] arr'.
 
C

chris

Method said:
Say I want to allocate a 10 element integer array. Here is the old C method:

int* arr = malloc(10 * sizeof (*arr));

Here is the C++ method:

int arr[] = new int[10];

Is there any difference between the two methods? What about when
deallocating the memory? It seems to me that, in this case, 'free(arr)'
would be faster than 'delete[] arr'.

Actually, delete[] arr and free(arr) should be identical.

The only place where delete[] should do something interesting is where
the vector of objects you are deleting have a non-trivial destructor, at
which point it will be called.

Chris
 
R

Ron Natalie

Method said:
Say I want to allocate a 10 element integer array. Here is the old C method:

int* arr = malloc(10 * sizeof (*arr));

Here is the C++ method:

int arr[] = new int[10];

Is there any difference between the two methods? What about when
deallocating the memory? It seems to me that, in this case, 'free(arr)'
would be faster than 'delete[] arr'.
Yeah, the latter is ill-formed.

int* arr = new int[10];
 
R

Ron Natalie

chris said:
Actually, delete[] arr and free(arr) should be identical.

The only place where delete[] should do something interesting is where
the vector of objects you are deleting have a non-trivial destructor, at
which point it will be called.>
Chris

You can't rely on this.
 
D

David Lindauer

Method said:
Say I want to allocate a 10 element integer array. Here is the old C method:

int* arr = malloc(10 * sizeof (*arr));

Here is the C++ method:

int arr[] = new int[10];

Is there any difference between the two methods? What about when
deallocating the memory? It seems to me that, in this case, 'free(arr)'
would be faster than 'delete[] arr'.

with malloc() you have to check the data got allocated. new() may thrown an
exception or call your new_handler. Also, the C++ method is more clear in terms
of what exactly you are attempting to do.

David
 
A

Andrew Koenig

Method Man said:
Say I want to allocate a 10 element integer array. Here is the old C
method:
int* arr = malloc(10 * sizeof (*arr));
Here is the C++ method:
int arr[] = new int[10];
Is there any difference between the two methods? What about when
deallocating the memory? It seems to me that, in this case, 'free(arr)'
would be faster than 'delete[] arr'.

You shouldn't be worrying about timing unless you have measured your program
and proved it's a problem.

Let me change your example slightly:

std::string* arr = malloc(10 * sizeof(*arr));

vs.

std::string* arr = new std::string[10];

Now the second example works and the first one doesn't.

But realistically, you should probably eschew both of these forms in favor
of

std::vector<int> arr(10);

or

std::vector<std::string> arr(10);

depending on which element type you prefer, because it's easier to write,
the memory gets deallocated automatically, and vectors are generally more
flexible than "arrays" allocated either by new or by malloc.
 
A

Andrew Koenig

Actually, delete[] arr and free(arr) should be identical.

I don't know why you say that. I don't think there is anything in the C++
standard that prohibits the implementation from using two totally different
allocators for delete and free.
 
M

Method Man

Ron Natalie said:
Method said:
Say I want to allocate a 10 element integer array. Here is the old C method:

int* arr = malloc(10 * sizeof (*arr));

Here is the C++ method:

int arr[] = new int[10];

Is there any difference between the two methods? What about when
deallocating the memory? It seems to me that, in this case, 'free(arr)'
would be faster than 'delete[] arr'.
Yeah, the latter is ill-formed.

int* arr = new int[10];

Oops. I must have flash-backed to coding in Java. :)
 
K

Kante Mamadou Moustapha

Method Man a écrit :
Say I want to allocate a 10 element integer array. Here is the old C method:

int* arr = malloc(10 * sizeof (*arr));

Here is the C++ method:

int arr[] = new int[10];

Is there any difference between the two methods? What about when
deallocating the memory? It seems to me that, in this case, 'free(arr)'
would be faster than 'delete[] arr'.

and as someone said for delete, if you try to allocate an object that
has not a trivial constructor, new will call it and not malloc. So if
its basic types, no difference (new and delete works as malloc and free)
otherwise, you should use new and delete.
And something else, if you decide to code in C++, why using c libraries?
use C++ library, it's more clear, except for some low level instructions
(as manipulate files, I prefer c ones to C++ ones).
 
S

Siemel Naran

chris said:
Method Man wrote:
Say I want to allocate a 10 element integer array. Here is the old C method:

int* arr = malloc(10 * sizeof (*arr));

Here is the C++ method:

int arr[] = new int[10];

Is there any difference between the two methods? What about when
deallocating the memory? It seems to me that, in this case, 'free(arr)'
would be faster than 'delete[] arr'.

Actually, delete[] arr and free(arr) should be identical.

They need not be the same, and on MSVC 7 it appears that they are different
(at least in the debug build as I've stepped through the code). Also, the
user can replace the default operator new and operator delete with their own
functions.

So a related question. Why provide your own operator new and delete?
Reasons I can think of: to write your own memory allocation strategy -- but
then again, why not just override class operator new and class operator
delete, or provide custom allocators; and as someone told me once to
implement garbage collection -- though I don't see how this would work.
 
J

JKop

Let me change your example slightly:

std::string* arr = malloc(10 * sizeof(*arr));

vs.

std::string* arr = new std::string[10];

Now the second example works and the first one doesn't.


Unless ofcourse...

std::string* strings = malloc( 10 * sizeof(std::string) );

new(&strings[0]) std::string;
new(&strings[1]) std::string;
new(&strings[2]) std::string;
new(&strings[3]) std::string;
new(&strings[4]) std::string;
new(&strings[5]) std::string;
new(&strings[6]) std::string;
new(&strings[7]) std::string;
new(&strings[8]) std::string;
new(&strings[9]) std::string;

//Play with the strings


//Finished playing with the strings

strings[0].~std::string();
strings[1].~std::string();
strings[2].~std::string();
strings[3].~std::string();
strings[4].~std::string();
strings[5].~std::string();
strings[6].~std::string();
strings[7].~std::string();
strings[8].~std::string();
strings[9].~std::string();

free(strings);


Ofcourse, an automatic storage duration array of type "char" could've been
used in the above instead of dynamic memory allocation.


-JKop
 
J

JKop

int arr[] = new int[10];


Only three places in which object_name[] is allowed:

(I'm pretty sure about this, but I'm open to correction)


A) Function arguments:

int main( int argc, char* argv[] );


B) Function return value:

int[] Blah();


C) Initializing an aggregate:

int k[] = { 1, 2, 3, 4, 5, 6 };

char blah[] = "blah";


-JKop
 
C

chris

Andrew said:
Actually, delete[] arr and free(arr) should be identical.


I don't know why you say that. I don't think there is anything in the C++
standard that prohibits the implementation from using two totally different
allocators for delete and free.

I apologise, I should have been clearer. According to the standard the
two may be implemented totally differently. However in many
implementations (including gcc's and vc++6), delete just calls free. It
is reasonable as a first approximation to assume the two will perform as
close in performance as to not matter. :)

Chris
 
A

Arijit

JKop said:
[snip]

std::string* strings = malloc( 10 * sizeof(std::string) );

new(&strings[0]) std::string;
new(&strings[1]) std::string;
new(&strings[2]) std::string;
new(&strings[3]) std::string;
new(&strings[4]) std::string;
new(&strings[5]) std::string;
new(&strings[6]) std::string;
new(&strings[7]) std::string;
new(&strings[8]) std::string;
new(&strings[9]) std::string;


I don't think explicit calling of constructors is allowed, though I could
be wrong.

//Play with the strings


//Finished playing with the strings

strings[0].~std::string();
strings[1].~std::string();
strings[2].~std::string();
strings[3].~std::string();
strings[4].~std::string();
strings[5].~std::string();
strings[6].~std::string();
strings[7].~std::string();
strings[8].~std::string();
strings[9].~std::string();


Don't do this. Explicit calling of destructors is allowed for a very special
reason, and it should not be abused.

- Arijit
 
A

Arijit

In any declaration, [] is allowed, not just function declaration. For example

typedef int arr_int[];

which reads: arr_int is an array of type int.

However, its not possible to declare a variable of type arr_int, though
you can declare a pointer of type arr_int. In fact, you can't even do a
sizeof on arr_int.

-Arijit

JKop said:
int arr[] = new int[10];


Only three places in which object_name[] is allowed:

(I'm pretty sure about this, but I'm open to correction)


A) Function arguments:

int main( int argc, char* argv[] );


B) Function return value:

int[] Blah();


C) Initializing an aggregate:

int k[] = { 1, 2, 3, 4, 5, 6 };

char blah[] = "blah";


-JKop
 
J

JKop

Arijit posted:
JKop said:
[snip]

std::string* strings = malloc( 10 * sizeof(std::string) );

new(&strings[0]) std::string;
new(&strings[1]) std::string;
new(&strings[2]) std::string;
new(&strings[3]) std::string;
new(&strings[4]) std::string;
new(&strings[5]) std::string;
new(&strings[6]) std::string;
new(&strings[7]) std::string;
new(&strings[8]) std::string; new(&strings[9]) std::string;


I don't think explicit calling of constructors is allowed, though I
could be wrong.


You are. Some people's explanation of "placement new" is that it constructs
an object at a particular place in memory. My own explanation of it is that
is calls constructors.


Out of curiosity, if it were illegal to explicitly call a constructor, then
what is the function of "placement new"?

strings[0].~std::string(); strings[1].~std::string();
strings[2].~std::string(); strings[3].~std::string();
strings[4].~std::string(); strings[5].~std::string();
strings[6].~std::string(); strings[7].~std::string();
strings[8].~std::string(); strings[9].~std::string();


Don't do this. Explicit calling of destructors is allowed for a very
special reason, and it should not be abused.


My code does not "abuse". My code:

A) Allocates memory

B) Calls constructor

C) Calls destructor

D) Deallocates memory


The only place where my above code could fall down is if an object of the
class "std::string" had to reside in a particular place in memory, like at a
boundary or whatever.


As to there being a very special reason, my code *is* that very special
reason - I'm doing everything manually. I'm allocating the memory by myself,
I'm calling the constructor by myself, and I'm calling the destructor by
myself, etc.

Here's actually a nice use for it:


void SomeFunc(int const a)
{
//This function will define an object of type "std::string".
//The particular constructor it calls is dependent upon
//the supplied argument "a".

//This can be achieved with dynamic memory allocation:

std::string* p_str;

switch (a)
{
case 1:

p_str = new std::string(... // a particular constructor
break;

case 2;

p_str = new std::string(... // a different constructor
break;

... //and so on
}

//Work with the string


//Finished working with the string

delete p_str;
}


Ofcourse, in the above, the dynamic memory allocation is unnecessary.


void SomeFunc(int const a)
{
char blah[ sizeof(std::string) ];

switch (a)
{
case 1:
new(blah) std::string(...
break;

case 2:
new(blah) std::string(...
...
}

std::string& str = *reinterpret_cast< std::string* const > ( static_cast
<char* const>(blah) );

//Now we can use "str" just like an "std::string"

...


//Cleanup time:

str.~std::string();
}


-JKop
 
S

Siemel Naran

JKop said:
As to there being a very special reason, my code *is* that very special
reason - I'm doing everything manually. I'm allocating the memory by myself,
I'm calling the constructor by myself, and I'm calling the destructor by
myself, etc.

Here's actually a nice use for it:


void SomeFunc(int const a)
{
//This function will define an object of type "std::string".
//The particular constructor it calls is dependent upon
//the supplied argument "a".

//This can be achieved with dynamic memory allocation:

std::string* p_str;

switch (a)
{
case 1:

p_str = new std::string(... // a particular constructor
break;

case 2;

p_str = new std::string(... // a different constructor
break;

... //and so on
}

A nit. Unless there is a default case, or you handle every possible int
that could occur in your situation, it might be nice to initialize p_str to
NULL.

On the other hand, perhaps the function is doing too much: namely creating a
special string, and then working with the string. Maybe it's better to
write one function that returns a new string (whether by value, pointer,
auto_ptr, etc), and another that works with the string. Then this whole
argument disappears.
//Work with the string


//Finished working with the string

delete p_str;
}


Ofcourse, in the above, the dynamic memory allocation is unnecessary.


void SomeFunc(int const a)
{
char blah[ sizeof(std::string) ];

switch (a)
{
case 1:
new(blah) std::string(...
break;

Oops. This is unsafe. On many platforms, char is aligned on addresses that
are a multiple of 1 (that is, any address), while pointers and ints (which
is basically what a std::string is) are aligned on addresses that are a
multiple of 4. The standard solution to this problem is to use a union and
include every known fundamental type in the union (though in theory this
can't work either as implementations may introduce their own fundamental
types), so change:
char blah[ sizeof(std::string) ];

to

union
{
char blah[ sizeof(std::string) ];
long double __longdouble;
double __double;
long __long;
int __int;
void * __voidstar;
void (* __functionpointer)();
void (std::eek:stream::* __memberpointer)();
};

Stricly speaking my code is not conforming as I use identifiers starting
with two underscores.
case 2:
new(blah) std::string(...
...
}

std::string& str = *reinterpret_cast< std::string* const > ( static_cast
<char* const>(blah) );

//Now we can use "str" just like an "std::string"

...


//Cleanup time:

str.~std::string();
}

While correct, except for the alignment part, the style seems too technical
for normal end user code.
 
M

Method Man

Does the FAQ "[16.2] Can I free() pointers allocated with new? Can I
delete pointers allocated with malloc()?" (Freestore management)
contain the answer for your question?
http://www.fmi.uni-konstanz.de/~kuehl/c++-faq/freestore-mgmt.html#faq-16.2

It's not quite what I was after. But I found "[16.4] Can I use realloc() on
pointers allocated via new?" interesting to read. Here's the partial answer
from the FAQ:

"No! When realloc() has to copy the allocation, it uses a bitwise copy
operation, which will tear many C++ objects to shreds."

I don't see the problem with copying objects bit-by-bit. It's ok for structs
isn't it? Can someone shed some light?
 
P

Paul

Method Man said:
I don't see the problem with copying objects bit-by-bit. It's ok for structs
isn't it? Can someone shed some light?
Method Man said:
pointers allocated via new?" interesting to read. Here's the partial answer
from the FAQ:

I don't see the problem with copying objects bit-by-bit. It's ok for structs
isn't it? Can someone shed some light?

Read the rest of the FAQ. For example, what if the object is
reference-counted? You don't update the reference count if you blindly copy
the object by using realloc(). Some implementations use reference counted
std::string's. If you bypass the copy-assign operators, you will
undoubtedly render the string object(s) unstable.

In general, that's why there is such a thing as a user-defined copy
constructor and assignment operator. They are there for a purpose, and that
purpose is to do something important if the object is copied or assigned.

-Paul
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top