Malloc and constructors
Er...use new
? That's kind of the point. You can also call the constructor explicitly, but there's little reason to do it that way
Using new/delete normally:
A* a = new A();
delete a;
Calling the constructor/destructor explicitly ("placement new"):
A* a = (A*)malloc(sizeof(A));
new (a) A();
a->~A();
free(a);
Malloc in constructors
First of all, you do not need a Heap*
member variable inside your Heap
object, and you certainly should not be allocating memory for it in the Heap
constructor - that's just asking for trouble. Nor should you be accessing your member variables as H->Elements
, but rather simply as Elements
.
The only thing you need to allocate is the Elements
array.
With regards to handling allocation failures, constructors should indicate failures via an exception. There is even a standard exception type, std::bad_alloc
that is usually used to indicate a failure to allocate memory.
For example:
#include <stdexcept> // for std::bad_alloc
...
Heap::Heap (int maxElements)
{
Elements = ( ElementType* ) malloc ( ( maxElements+1 )*sizeof ( ElementType ) );
if (Elements == NULL)
throw std::bad_alloc("Failed to allocate memory");
...
}
Even better, use new
rather than malloc
to allocate the memory. new
will automatically throw an exception of type std::bad_alloc
if it fails to allocate memory.
Example:
Heap::Heap (int maxElements)
{
Elements = new ElementType[maxElements + 1]; // throws std::bad_alloc on failure
...
}
Note: if you use new
to allocate the object, you must use delete
to free it rather than free
. (Correction: In the example above, you are using the array form of new, new[]
, so you should call the array form of delete, delete[]
).
Finally, you haven't shown how ElementType
is declared, but if it's a type that has a non-default constructor/destructor (or if it's a template parameter which means it can potentially be such a type), you have to use new
rather than malloc
when allocating it because malloc
will not call the constructor (and free
will not call the destructor). In general, it's good practice to just always use new
and delete
in C++ rather than malloc
and free
.
Calling constructor of class member when using malloc
malloc
is a C function, and has no knowledge of classes, constructors, etc.
If you are dead-set on using this, you are going to have to always call placement new
on each object (note: this requires including the header <new>
), and also manually calling the destructor before deallocating. You will also need to store the pointer that is returned from placement new
in order to avoid undefined behavior (as this is technically the only pointer that points to the start of the object's lifetime).
As you have in your edit, it will look something like:
auto cls = static_cast<MyClass*>(std::malloc(sizeof(MyClass)));
cls = new(cls) MyClass(/* any arguments here ... */);
cls->value = "hello";
cls->~MyClass();
std::free(cls);
However, be aware that by using malloc
you actually introduce other issues with respect to exception safety. If your placement-new
call throws an exception, the memory allocated by std::malloc
will leak -- which is bad. You also wouldn't want placement new
to operate on nullptr
if malloc
returns null, and would need to convey this error -- perhaps through an exception. You will probably want to wrap this into a helper that will ensure these conditions can't happen:
#include <new> // placement-new, std::bad_alloc
#include <utility> // std::forward
#include <cstdlib> // std::malloc, std::free
template <typename T, typename...Args>
T* make(Args&&...args)
{
auto* p = static_cast<T*>(std::malloc(sizeof(T)));
// Placement new can't operate on nullptr
if (p == nullptr) {
// alternatively, this could be 'return nullptr' if not using exceptions
throw std::bad_alloc{};
}
try {
p = new (p) T(std::forward<Args>(args)...);
} catch (...) {
std::free(p);
throw; // rethrow the exception here
}
return p;
};
Similarly, you will likely want to have a way to destroy objects while deallocating them, so that resources aren't leaked:
template <typename T>
void dispose(T* p)
{
p->~T();
std::free(p);
}
Using these utilities, the above example now becomes:
auto cls = make<MyClass>(/* any arguments here ... */);
cls->value = "hello";
dispose(cls);
If this seems like an awful lot of boilerplate, this is because this is exactly what new
and delete
already does for you. If you can, you will be much better off using these facilities when dealing with C++ types. This also allows you to continue using other RAII-wrappers like smart pointers easily without having to manually specify allocators (shared_ptr
) or deleters (unique_ptr
).
There really isn't a good reason IMO to prevent using new
and delete
in favor of malloc
/free
when working with C++ code. If you have a library that exposes a C-only interface but is implemented in C++ code -- it would actually be better for you to internalize the allocations and switch to new
and delete
rather than using malloc
and free
so you can save yourself the hassle.1
One other thing to be aware of is that if the types allocated in your system ever have a custom alignment via alignas
that exceeds alignof(std::max_align_t)
, using std::malloc
will be undefined behavior because it will be unable to satisfy the alignment requirements. This is another thing that new
/delete
would take care of for you.
1 If your "mixed C++/C" code is exposing a C interface at some point, it would be much cleaner for you to use new
and delete
rather than malloc
, and to simply expose the creation/deletion functions on your API explicitly. For example:
// C header:
extern "C"
my_class* make_my_class(void);
extern "C"
void dispose_my_class(my_class* p);
// C++ implementation:
extern "C"
my_class* make_my_class(void)
{
return new my_class{ ... };
}
extern "C"
void dispose_my_class(my_class* p)
{
delete p;
}
This is generally the approach taken for C/C++ interop.
malloc and constructors in c++
malloc
allocates raw memory. There's no point in trying to pass constructor arguments to it because it doesn't call any constructors.
If you have to work with raw memory, it is up to you to construct an object in previously allocated raw memory by using "placement new" syntax
...
void *raw_b = malloc(sizeof *b);
b = new(raw_b) B_Class(c1, c2, c3); // <- placement new
...
Numerically, the value of b
will be the same as raw_b
, i.e. it is possible to get by without an extra raw_b
pointer. But I prefer to do it this way, with an intermediate void *
pointer, to avoid ugly casts.
Be careful when destroying such objects, of course. Custom allocation requires custom deletion. You can't just delete
your b
in general case. A symmetrical custom deletion sequence would involve an explicit destructor call followed by raw memory deallocation
b->~B_Class(); // <- explicit destructor call
free(b);
P.S. You might consider going a different route: overloading operator new
/operator delete
in your class instead of spelling out custom allocation explicitly every time you need to create an object.
malloc within constructor safe?
malloc
/new
within a constructor is safe, provided you follow the rule of three. With malloc
/new
you now have a resource that you have to explicitly take care to release at the right times.
Therefore: you must define a copy constructor, an assignment operator, and a destructor that will free
the memory. If you don't, the class can be misused and cause you a lot of problems.
If you want to avoid having to define these extra functions, use std::vector
instead, which handles them for you.
Using new with C++ Constructors that use C malloc
Yes you can, but you should have a strong reason. The
new
operator invokes the constructor which in many ways is just like a regularclass
method. You should also add thefree()
part to the destructor.But please note, that if you
malloc()
a c++ object the constructor of that object will not be called. I think there are very few reasons to callmalloc()
in a c++ program: you probably wish torealloc()
later, which is one reason. But you can always use native c++ objects like stl containers.It's not unsafe to use the two ways of allocating memory in a c++ program, you just have to be careful not to
malloc()
something and thendelete
it ornew
something and thenfree()
it. But withmalloc()
you ALWAYS have to be careful about many things like it returningNULL
andfree()
ing the allocated memory so it's not an extra thing.Once again, the most dangerous thing you can do is
malloc()
a c++ object. Because as I already said, the constructor won't be called.
C++ constructor: which exception type should I throw when malloc fails to allocate memory
The most appropriate exception would be to throw std::bad_alloc
; however it is strongly discouraged to use malloc
unless you have a good reason to -- and so I would advise against throwing this explicitly.
If you absolutely need heap memory, you should be using new
/delete
-- which will automatically invoke constructors/destructors, start/end object lifetimes, and will throw a std::bad_alloc
when out of memory for you. std::malloc
will result in undefined behavior for any non-trivial types because it doesn't formally start an object's lifetime.
Better yet, c++11 has been out for over ten years, so use std::unique_ptr
and, if you have c++14, use std::make_unique
so you don't even need new
directly. unique_ptr
will prevent memory leaks by ensuring that delete
is called on the allocated pointer if the pointer is not-null.
This would now look like:
#include <memory>
// Note: 'typedef struct' does nothing in C++ -- there is no need for it
struct Point {
float x;
float y;
};
class Foo {
private:
std::unique_ptr<Point> p;
public:
Foo ()
: p{std::make_unique<Point>()}
{
}
};
Aside from the above answer: You shouldn't really use heap memory unless you really have a need for objects with dynamic lifetime. In the code you provided, it looks like it may be more appropriate to just hold the Point
by value anyway:
class Foo {
private:
Point p;
public:
Foo ()
: p{} // no allocation needed
{
}
};
Related Topics
C++11: How to Alias a Function
What Is the Best Encryption Library in C/C++
Why Is It Undefined Behavior to Delete[] an Array of Derived Objects via a Base Pointer
How Is a Vector's Data Aligned
How to Check If an Object's Type Is a Particular Subclass in C++
Why Does Cudamalloc() Use Pointer to Pointer
What's Faster, Iterating an Stl Vector with Vector::Iterator or with At()
Case Insensitive Std::String.Find()
C++ Convert Vector<Int> to Vector<Double>
Qt Signals (Queuedconnection and Directconnection)
How Does C++ Stl Unordered_Map Resolve Collisions
How to Get a Random Element from a C++ Container
How to Find the Size of an Int[]
When Is Overloading Pass by Reference (L-Value and R-Value) Preferred to Pass-By-Value
How to Define a C++ Preprocessor MACro Through the Command Line with Cmake