Making "new" out of "malloc"

Yeah, that's not a particularly fantastic title, but it's the best I could come up with.
1
2
3
4
5
6
7
8
9
10
11
// Construction
Class* x = (Class*)malloc(sizeof(Class) * 3);
for (uint i = 0; i < 3; i++) *x[i] = Class();

Class* x = new Class[3];

// Destruction
for (uint i = 0; i < 3; i++) x.~Class();
free(x);

delete[] x;
Are these equivalent?
I'm asking because I'd like to use realloc, among other things, in C++.
Last edited on
Don't go down that dark, slippery path of thought.

Here is a yellow brick road that contains construction, destruction, and reallocates too:
1
2
3
{
  std::vector<Class> x( 3 );
}
don't tell him that he shouldn't learn the basics if he is interested...
I think it is quite important to learn the old c-stuff to have a better understanding about the c++ standard libary.

Nah, that's not completely the same.
new constructs an object on the heap and calls the constructor for that object.
Malloc just allocates memory of the desired size (and does not call the constructor).

You try to invoke the constructor in the for loop after the allocation of the memory and this simulates the behaviour quite good, but you have to be careful about doing that, excepecially when managing Memory in that class.
The allocated memory should be deleted when the destructor is invoked and the location where x[i] points to is immediately destroyed after it is being initialized because the rvalue object Class() is on the Stack and goes out of scope in each iteration of the loop

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// Example program
#include <iostream>

class Class
{
public:
    Class() {std::cout << "ctor" << std::endl;}
    Class& operator=(const Class&) {std::cout << "copy assignment" << std::endl; return *this;} // invoked when not using c++11
    Class& operator=(Class&&) {std::cout << "move assignment" << std::endl; return *this;} // invalid when not using c++11
    ~Class() {std::cout << "dtor" << std::endl;}
    
};

int main()
{
    std::cout << "malloc" << std::endl;
    // Construction
    Class* x = (Class*)malloc(sizeof(Class) * 3);
    for (uint i = 0; i < 3; i++) x[i] = Class(); // prints ctor, move assignment and dtor 3 times
    
    // Destruction
    for (uint i = 0; i < 3; i++) x[i].~Class(); // prints 3* dtor
    free(x);
    
    std::cout << "\nnew" << std::endl;
    x = new Class[3];
    delete[] x;
    // prints 3* ctor and 3* dtor
}


You ended up constructing 3 elements with malloc and deleting 6 of them, this shouldn't be what you want.

Note that there is no c-only-way to call a constructor because constructors didn't exist in C.
Therefore C++ introduced the keyword new to construct the objects on the heap.
C++ also introduced placement new to initialize objects on the heap when the memory is allready allocated:
for (uint i = 0; i < 3; i++) new((void*)&x[i]) Class();
Last edited on
You ended up constructing 3 elements with malloc and deleting 6 of them, this shouldn't be what you want.
Is there any way to make the two exactly equivalent? As I said, I'd like to be able to use realloc in case two PushBacks are executed consecutively - as far as I've understood it, using new[] never expands the array to the adjacent area in memory, unlike realloc.
using new[] never expands the array to the adjacent area in memory, unlike realloc
both new and realloc/malloc allways allocate contiguous memory.

But there is still a way to accomplish this with malloc/realloc by using placement new as shown at the end of my previous post, In fact most of the STL containers use malloc and placement new internally because they'd have to realocate memory every time you add an element to the container.
Note: You should still prefer new/delete over malloc/free if possible (most of the times).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Example program
#include <iostream> // std::cout
#include <cstdlib> // malloc
#include <new> // placement new

class Class
{
public:
    Class() {std::cout << "ctor" << std::endl;}
    ~Class() {std::cout << "dtor" << std::endl;}
    
};

int main()
{
    std::cout << "malloc" << std::endl;
    // Construction
    Class* x = (Class*)malloc(sizeof(Class) * 3);
    for (uint i = 0; i < 3; i++) 
        new((void*)&x[i]) Class(); // prints 3*ctor

    // Destruction
    for (uint i = 0; i < 3; i++) x[i].~Class(); // prints 3*dtor
        free(x);
}

Last edited on
Stroustrup:
Why doesn't C++ have an equivalent to realloc()?

If you want to, you can of course use realloc(). However, realloc() is only guaranteed to work on arrays allocated by malloc() (and similar functions) containing objects without user-defined copy constructors. Also, please remember that contrary to naive expectations, realloc() occasionally does copy its argument array.
In C++, a better way of dealing with reallocation is to use a standard library container, such as vector, and let it grow naturally.
http://www.stroustrup.com/bs_faq2.html#renew

Can I mix C-style and C++ style allocation and deallocation?

Yes, in the sense that you can use malloc() and new in the same program.
No, in the sense that you cannot allocate an object with malloc() and free it using delete. Nor can you allocate with new and delete with free() or use realloc() on an array allocated by new.

The C++ operators new and delete guarantee proper construction and destruction; where constructors or destructors need to be invoked, they are. The C-style functions malloc(), calloc(), free(), and realloc() doesn't ensure that. Furthermore, there is no guarantee that the mechanism used by new and delete to acquire and release raw memory is compatible with malloc() and free(). If mixing styles works on your system, you were simply "lucky" - for now.

If you feel the need for realloc() - and many do - then consider using a standard library vector. For example
1
2
3
4
5
	// read words from input into a vector of strings:

	vector<string> words;
	string s;
	while (cin>>s && s!=".") words.push_back(s);

The vector expands as needed.
See also the examples and discussion in "Learning Standard C++ as a New Language", which you can download from my publications list.
http://www.stroustrup.com/bs_faq2.html#realloc


Alexandrescu:
The Mallocator
No, it's not the title of a Hollywood movie — it's just an std-like allocator based on malloc.

Let's start by making an observation: realloc is not entirely unusable to C++; it's just unusable with a subset of C++'s types. So even within the confines of the scarce Standard C API, you can safely use realloc with any POD, including all primitive types. Thus, in order to reap fast reallocation for our buffer class, we need to do the following:

A) Figure out whether an arbitrary type T is a POD or not.

B) Define a malloc-based allocator that has the same interface as std::allocator and adds a reallocate function. For PODs, the new allocator uses realloc directly; for non-PODs, it returns "uh-uh," in which case the caller must proceed with the classic allocate-copy-discard sequence.

C) Provide a method to interrogate an allocator: "Are you able to reallocate?" To that question, std::allocator must answer "No." Rub: you cannot touch std::allocator.
http://www.drdobbs.com/generic-typed-buffers-iii/184403806


Note: slightly dated, these were written before move semantics became central to C++.
But there is still a way to accomplish this with malloc/realloc by using placement new as shown at the end of my previous post, In fact most of the STL containers use malloc and placement new internally because they'd have to realocate memory every time you add an element to the container.
How would this be done using new[], then?
How would this be done using new[], then?

use operator new[] instead of operator new:

// Example program
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream> // std::cout
#include <cstdlib> // malloc

class Class
{
public:
    Class() {std::cout << "ctor" << std::endl;}
    ~Class() {std::cout << "dtor" << std::endl;}
};

int main()
{
    std::cout << "malloc" << std::endl;
    // Construction
    Class* x = (Class*)malloc(sizeof(Class) * 3);
    new((void*)x) Class[3]; // prints 3*ctor

    // Destruction
    for (uint i = 0; i < 3; i++) x[i].~Class(); // prints 3*dtor
        free(x);
}
Last edited on
don't tell him that he shouldn't learn the basics if he is interested...
I think it is quite important to learn the old c-stuff to have a better understanding about the c++ standard libary

I can not tell whether he is actually interested in the basics. It could as well be that he isn't aware of what the standard library already implements for him, because the learning has only covered the "c-stuff" so far.

One can write custom allocators for the standard library containers. Yes, at that point placement new & co is something one has to know, and yes, one must understand the "raw stuff under the hood" in order to know why the default allocator isn't optimal for some particular use case.


Lets assume that one has a function that does
1. Allocate
2. Use
3. Deallocate

Lets further assume that the Use returns or throws exception that is handled by the caller. Was the Deallocate skipped? The program continues and calls the function multiple times. How much memory can leak?

A standard library container (vector) does deallocate.
A standard library smart pointer that manages memory allocated with new does deallocate.
A raw pointer -- your code has to explicitly call delete/free on all exit paths.

@Schulter: What is the real "why" in your case?
use operator new[] instead of operator new

No, I mean "how can this be done using new instead of malloc. I apologize if I am being unclear.
No, I mean "how can this be done using new instead of malloc. I apologize if I am being unclear.

If you want to know how to simulate realloc you need 3 steps:
1. make an array of the desired new length
2. move the old array
3. free the old array
4. let the old pointer point to the new location
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream> // std::cout

class Class
{
public:
    Class() {std::cout << "ctor" << std::endl;}
    Class& operator=(Class&&) {std::cout << "move assignment" << std::endl; return *this;}
    ~Class() {std::cout << "dtor" << std::endl;}
};

int main()
{
    std::cout << "new" << std::endl;
    // Construction
    std::cout << "make 3" << std::endl;
    Class* x = new Class[3];
    
    { // realloc
        std::cout << "reallocate to 5" << std::endl;
        Class* temp = new Class[5];
        std::move(x, x+3, temp);
    
        std::cout << "delete previous 3" << std::endl;
        delete[] x;
        x = temp;
    }
    
    std::cout << "delete 5" << std::endl;
    delete[] x;
}

Note that move assignment operator is automatically created by the compiler if no copy-constructor, move-constructor, copy-assignment-operator and no destructor is declared.
Last edited on
Gamer's program prints:
new
make 3
ctor
ctor
ctor
reallocate to 5
ctor
ctor
ctor
ctor
ctor
move assignment
move assignment
move assignment
delete previous 3
dtor
dtor
dtor
delete 5
dtor
dtor
dtor
dtor
dtor

The vector variant (requires copy or move ctor):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream> // std::cout
#include <vector> // std::vector

class Class
{
public:
    Class() {std::cout << "ctor" << std::endl;}
    Class& operator=(Class&&) {std::cout << "move assignment" << std::endl; return *this;}
    ~Class() {std::cout << "dtor" << std::endl;}
    Class(Class&&) {std::cout << "move ctor" << std::endl;}
};

int main()
{
    std::cout << "vector" << std::endl;
    // Construction
    std::cout << "make 3" << std::endl;
    std::vector<Class> x(3);
    
    { // realloc
        std::cout << "reallocate to 5" << std::endl;
        std::cout << "delete previous 3 (if necessary)" << std::endl;
        x.resize( 5 );
    }
    
    std::cout << "delete 5" << std::endl;
}

vector
make 3
ctor
ctor
ctor
reallocate to 5
delete previous 3 (if necessary)
move ctor
move ctor
move ctor
ctor
ctor
dtor
dtor
dtor
delete 5
dtor
dtor
dtor
dtor
dtor
Last edited on
Good to know, but keep in mind that Vector has additional knowledge about the data being recreated.
This looks a littl bit messy now (std::move(x[1-3])) but it prints the same as vector and when wrapping this around a class it could look a bit better.

Also note that vector may use placement new and malloc internally so completely recreating the behaviour of vector might be impossible with only new/delete;.
I don't disagree on using vector being a good Idea, you should use it whenever you need contiguous memory and you should try to avoid making your own containers as long as the STL provides a container with similar interface.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream> // std::cout

class Class
{
public:
    Class() {std::cout << "ctor" << std::endl;}
    Class& operator=(Class&&) {std::cout << "move assignment" << std::endl; return *this;}
    Class (Class&&) {std::cout << "move" << std::endl;}
    ~Class() {std::cout << "dtor" << std::endl;}
};

int main()
{
    std::cout << "new" << std::endl;
    // Construction
    std::cout << "make 3" << std::endl;
    Class* x = new Class[3];
    
    { // realloc
        std::cout << "reallocate to 5" << std::endl;
        Class* temp = new Class[5]{std::move(x[0]), std::move(x[1]), std::move(x[2])};
    
        std::cout << "delete previous 3" << std::endl;
        delete[] x;
        x = temp;
    }
    
    std::cout << "delete 5" << std::endl;
    delete[] x;
}


Still keep in mind that you should only do this for learning and not for bigger programms.
As the others mention you should use a container from the STL if you don't have to implement your own container class.
Last edited on
All right, I think I understand it now. Thank you.
Topic archived. No new replies allowed.