Managing destructors with pre-allocated memory and arrays - c++

Hello So I'm experimenting with creating objects and arrays with preallocated memory. For instance I have this following code:
int * prealloc = (int*)malloc(sizeof(Test));
Test *arr = new(prealloc) Test();
Where test is defined as follows:
class Test {
public:
Test() {
printf("In Constructor\n");
}
~Test() {
printf("In Destructor\n");
}
int val;
};
In this scenario if I call delete it will actually release the memory which is bad, b/c maybe I'm using some type of memory manager so this will sure cause some problems. I searched in the internet and the only solution that I found was to call the destructor explicitly and then call free:
arr->~Test();
free(arr);
Is there another way to do this? is there perhaps a way to call delete and tell it to just call the destructor and not to release the memory?
My second problem was when working with arrays, like the previous example you can pass to new the pre-allocated memory:
int * prealloc2 = (int*)malloc(sizeof(Test) * 10);
Test *arr2 = new(prealloc2) Test[10];
If I call delete[] it will not only call the destructor for each element in the array but it will also release the memory which is something I don't want. The only way I have found that it should be done is to go through the array and call the destructor explicitly, and then call free. Like with the regular none array operators is there a way to tell the operator to just call the destructors without releasing the memory?
One thing I did notice was that the new operator for an array will actually use the first 4 bytes to store the size of the array (I only tested this in visual studio with a 32 bit build) That would help me know how many elements the array has but there is still one problem. What if the array is a pointer array? for example:
Test **arr2 = new Test*[10];
Could someone help me out with these questions please.

It's normal and expected to directly invoke the destructor to destroy objects you've created with placement new. As far as any other way to do things, about the only obvious alternative is to use an Allocator object (which, at least 99% of the time, will just be a wrapper around placement new and directly invoking the destructor).
Generally speaking, you do not want to use new[] at all. You typically want to allocate your raw memory with operator new (or possibly ::operator new) and release it with the matching operator delete or ::operator delete.
You create objects in that memory with placement new and destroy them by directly invoking the destructor.

There is no other way to do it but to explicitly call the destructor as delete will also attempt to free the memory.
Using preallocated memory with placement new should be fairly rare in your code - a typical use case is when you're dealing with direct memory mapped hardware interfaces when you want/need to map an object on top of a fixed memory address - and is something I'd normally consider a code smell.
If you want to tweak the memory management for a specific class, you're much better off either using an STL container with a custom allocator or overload operators new and delete for that specific class.

Yes, this is the only way to do it. There is an asymmetry in being allowed to define new but not delete. [ Well, you can do the latter but it can only get called when new throws an exception (not handled properly below!)
You can use a templated destroy to achieve the same result:
class Test
{
public:
Test() {
printf("In Constructor\n");
}
~Test() {
printf("In Destructor\n");
}
int val;
};
class Allocator
{
public:
static void* allocate(size_t amount) { return std::malloc(amount);}
static void unallocate(void* mem) { std::free(mem);}
static Allocator allocator;
};
Allocator Allocator::allocator;
inline void* operator new(size_t size, const Allocator& allocator)
{
return allocator.allocate(size);
}
template<class T>
void destroy(const Allocator& allocator, T* object)
{
object->~T();
allocator.unallocate(object);
}
int main()
{
Test* t = new (Allocator::allocator) Test();
destroy(Allocator::allocator, t);
return 0;
}

Related

Would there ever be a reason to initialize a pointer in a constructor with malloc?

As such:
class MyClass{
public:
int *property;
MyClass(){
property = (int*)malloc(sizeof(int));
}
~MyClass(){
free(property);
}
};
I understand that there are better ways to do this, but I don't think I understand why exactly this is incorrect.
Would there ever be a reason to initialize a pointer in a constructor with malloc?
At least couple of reasons comes to my mind:
you need to work with C code/library and pass pointer there that expected to be initialized by malloc()
You are limited with resources and want to be able to use realloc() with it
There could be more, but you need to be careful when working with raw pointers, either initialized by new or malloc(). For example your class violates rule of 3/5/0. Best way to handle that - use a smart pointer.
Also you need to remember that with malloc() you need to be sure that memory is properly initialized, it can be done with memset() or simple assignments with POD types or (and this is mandatory for non POD) through placement new. That usage is not trivial so you would want to deal with that when you really need it.
In general you should use new not malloc in c++ code. The only time not to do that is in extreme corner cases where you want to control exact location for some reason, building custom memory pools (and even then you should overload new so as not to call malloc directly in the class definition). In that case you use 'placement new'
The main reason to use new is that it will correctly construct the object that it just made. malloc will return garbage memory. Not relevant (maybe) for ints but certainly important for objects
You have to make sure to disable copy constructor/assignment operator which are generated by default in c++. If you don't, you will have undefined behavior. E.g. Below code will destruct twice.
#include<cstdlib>
static int number_of_constructions = 0;
static int number_of_destructions = 0;
struct S {
int * p;
S() {
p = (int*) malloc(sizeof(int));
number_of_constructions++;
}
~S() {
free(p);
number_of_destructions++;
}
};
void foo() {
S s;
S s2 = s;
}
Link: https://godbolt.org/g/imujg1

Initialise std::string in uninitialised, unowned memory

I'm using a C library (libwebsockets) which allows some user-data for each client. The library owns this memory, passes it as a void*, and my code reinterpret_cast's it to my user-data type.
I'm trying to add a std::string field to this class and am now seeing segfaults. Calling functions on this class causes errors, which is fair enough as it's likely backed by uninitialised memory.
How can I initialise that memory> I've tried assigning (the assignment operator segfaults) and calling various functions such as clear. I'm guessing there's a C++ mechanism for this.
Furthermore, how can the destructor be called when the string is no longer needed?
Assuming that you have a type something like this:
class MyType
{
std::string foo;
std::string bar;
};
And assuming that the void * points to an uninitialized allocation of at least sizeof(MyType) bytes, then you can construct it (and all contained objects) using placement new syntax:
void init_callback(void * ptr) {
new (ptr) MyType();
}
Similarly, you can destruct your type (which will destruct all contained objects) by calling the destructor directly.
void destroy_callback(void * ptr) {
MyType * mine = reinterpret_cast<MyType *>(ptr);
mine->~MyType();
}
Generally you don't call destructors directly, but you have to because you can't safely delete the pointer. The rule "every new should have one delete" has an analog in this situation: "every placement-new should have one explicit call to the destructor."
You can use placement-new to create an object in the provided memory:
std::string * s = new(memory) std::string;
and call the destructor to destroy it before reusing or releasing the memory:
s->std::string::~string();
If you find that a bit of a mouthful, then using std::string; will reduce it to s->~string();

Double free or corruption after queue::push

#include <queue>
using namespace std;
class Test{
int *myArray;
public:
Test(){
myArray = new int[10];
}
~Test(){
delete[] myArray;
}
};
int main(){
queue<Test> q
Test t;
q.push(t);
}
After I run this, I get a runtime error "double free or corruption". If I get rid of the destructor content (the delete) it works fine. What's wrong?
Let's talk about copying objects in C++.
Test t;, calls the default constructor, which allocates a new array of integers. This is fine, and your expected behavior.
Trouble comes when you push t into your queue using q.push(t). If you're familiar with Java, C#, or almost any other object-oriented language, you might expect the object you created earler to be added to the queue, but C++ doesn't work that way.
When we take a look at std::queue::push method, we see that the element that gets added to the queue is "initialized to a copy of x." It's actually a brand new object that uses the copy constructor to duplicate every member of your original Test object to make a new Test.
Your C++ compiler generates a copy constructor for you by default! That's pretty handy, but causes problems with pointer members. In your example, remember that int *myArray is just a memory address; when the value of myArray is copied from the old object to the new one, you'll now have two objects pointing to the same array in memory. This isn't intrinsically bad, but the destructor will then try to delete the same array twice, hence the "double free or corruption" runtime error.
How do I fix it?
The first step is to implement a copy constructor, which can safely copy the data from one object to another. For simplicity, it could look something like this:
Test(const Test& other){
myArray = new int[10];
memcpy( myArray, other.myArray, 10 );
}
Now when you're copying Test objects, a new array will be allocated for the new object, and the values of the array will be copied as well.
We're not completely out trouble yet, though. There's another method that the compiler generates for you that could lead to similar problems - assignment. The difference is that with assignment, we already have an existing object whose memory needs to be managed appropriately. Here's a basic assignment operator implementation:
Test& operator= (const Test& other){
if (this != &other) {
memcpy( myArray, other.myArray, 10 );
}
return *this;
}
The important part here is that we're copying the data from the other array into this object's array, keeping each object's memory separate. We also have a check for self-assignment; otherwise, we'd be copying from ourselves to ourselves, which may throw an error (not sure what it's supposed to do). If we were deleting and allocating more memory, the self-assignment check prevents us from deleting memory from which we need to copy.
The problem is that your class contains a managed RAW pointer but does not implement the rule of three (five in C++11). As a result you are getting (expectedly) a double delete because of copying.
If you are learning you should learn how to implement the rule of three (five). But that is not the correct solution to this problem. You should be using standard container objects rather than try to manage your own internal container. The exact container will depend on what you are trying to do but std::vector is a good default (and you can change afterwords if it is not opimal).
#include <queue>
#include <vector>
class Test{
std::vector<int> myArray;
public:
Test(): myArray(10){
}
};
int main(){
queue<Test> q
Test t;
q.push(t);
}
The reason you should use a standard container is the separation of concerns. Your class should be concerned with either business logic or resource management (not both). Assuming Test is some class you are using to maintain some state about your program then it is business logic and it should not be doing resource management. If on the other hand Test is supposed to manage an array then you probably need to learn more about what is available inside the standard library.
You are getting double free or corruption because first destructor is for object q in this case the memory allocated by new will be free.Next time when detructor will be called for object t at that time the memory is already free (done for q) hence when in destructor delete[] myArray; will execute it will throw double free or corruption.
The reason is that both object sharing the same memory so define \copy, assignment, and equal operator as mentioned in above answer.
You need to define a copy constructor, assignment, operator.
class Test {
Test(const Test &that); //Copy constructor
Test& operator= (const Test &rhs); //assignment operator
}
Your copy that is pushed on the queue is pointing to the same memory your original is. When the first is destructed, it deletes the memory. The second destructs and tries to delete the same memory.
You can also try to check null before delete such that
if(myArray) { delete[] myArray; myArray = NULL; }
or you can define all delete operations ina safe manner like this:
#ifndef SAFE_DELETE
#define SAFE_DELETE(p) { if(p) { delete (p); (p) = NULL; } }
#endif
#ifndef SAFE_DELETE_ARRAY
#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p) = NULL; } }
#endif
and then use
SAFE_DELETE_ARRAY(myArray);
Um, shouldn't the destructor be calling delete, rather than delete[]?

Placement new behaviour equivalent

I have a question regarding placement new syntax in C++. Are the following two code snippets functionally equivalent and can be used interchangeably (I am not implying that the second should be used, when the first one is suitable)?
#1
T* myObj = new T();
// Do something with myObj
delete myObj;
#2
char* mem = new char[sizeof(T)];
T* myObj = new (mem) T();
// Do something with myObj
myObj->~T();
delete[] mem;
Is there something I should be especially careful of, when I am using the placement new syntax like this?
They are not equivalent, because they have different behaviour if the constructor or the destructor of T throws.
new T() will free any memory that has been allocated before letting the exception propagate any further. char* mem = new char[sizeof(T)]; T* myObj = new (mem) T(); will not (and unless you explicitly do something to ensure that it gets freed you will have a leak). Similarly, delete myObj will always deallocate memory, regardless of whether ~T() throws.
An exact equivalent for T* myObj = new T();/*other code*/delete myObj; would be something like:
//When using new/delete, T::operator new/delete
//will be used if it exists.
//I don't know how do emulate this in
//a generic way, so this code just uses
//the global versions of operator new and delete.
void *mem = ::operator new(sizeof(T));
T* myObj;
try {
myObj = new (mem) T();
}
catch(...) {
::operator delete(mem);
throw;
}
/*other code*/
try {
myObj->~T();
::operator delete(mem);
}
catch(...) {
//yes there are a lot of duplicate ::operator deletes
//This is what I get for not using RAII ):
::operator delete(mem);
throw;
}
Since you're allocating raw memory, a closer equivalent would be:
void *mem = operator new(sizeof(T));
T *myobj = new(mem) T();
// ...
myobj->~T();
operator delete(mem);
Note that if you've overloaded ::operator new for a particular class, this will use that class' operator new, where yours using new char [] would ignore it.
Edit: though I should add that I'm ignoring the possibility of exceptions here. #Mankarse's answer seems (to me) to cover that part fairly well.
On a fundamental level, you're doing the same thing in both situations: i.e. you're instantiating a new object on the heap and you're releasing the memory, but in the second case you're (obviously) using the placement new operator.
In this case both of them would yield the same results, minus the differences if the constructor throws as Mankarse explained.
In addition, I wouldn't say that you can use them interchangeably, because the second case is not a realistic example of how placement new is used. It would probably make a lot more sense to use placement new in the context of a memory pool and if you're writing your own memory manager so you can place multiple T objects on the per-allocated memory (in my tests it tends to save about 25% CPU time). If you have a more realistic use case for placement new then there will be a lot more things that you should worry about.
Well, you are pre-allocating memory for your T object. And it should be fine. Nevertheless it makes sense if you will reuse allocated area one more time. Otherwise It will be slower.
Yes. Your example is too simple to demonstrate this, but the memory you allocated in advance, "mem," should manage the object stored within, "myObj."
Perhaps put a better way, scenario #1 allocates space on the heap, and constructs an object in that space. Scenario #2 allocates space on the heap, "mem," then constructs an object somewhere within that space.
Now, put a second object somewhere else within "mem." It gets complicated, right?
The construction and destruction of myObj are happening identically in both scenarios (except in the case of your constructor throwing an exception, as pointed out by Mankarse), but the allocator is taking care of your memory management for you in scenario #1, and not in scenario #2.
So, be careful of managing "mem" appropriately. One common approach is the following:
template<class T> void destroy(T* p, Arena& a)
{
if (p) {
p->~T(); // explicit destructor call
a.deallocate(p);
}
}

Are there any problems with this overload of operator new?

I was thinking about some memory pool/allocation stuff I might write so I came up with this operator new overload that I want to use to facilitate reuse of memory. I'm wondering if there are any problems you guys can think of with my implementation (or any other possible ones).
#include <cstddef>
namespace ns {
struct renew_t { };
renew_t const renew;
}
template<typename T>
inline void * operator new(std::size_t size, T * p, ns::renew_t renew_constant) {
p->~T();
return p;
}
template<typename T>
inline void operator delete(void *, T *, ns::renew_t renew_constant) { }
It can be used like this
int main() {
foo * p(new foo()); // allocates memory and calls foo's default constructor
new(p, ns::renew) foo(42); // calls foo's destructor, then calls another of foo's constructors on the same memory
delete p; // calls foo's destructor and deallocates the memory
}
Please read http://www.gotw.ca/gotw/022.htm and http://www.gotw.ca/gotw/023.htm.
Really, you should define operator= rather than playing games with destructors. And adding an operator new (and operator delete, YUCK!) overload into the mix only increases the pain.
And, as C++ god Herb Sutter recommends in those links, you can simply define constructors in terms of operator=.
SHOULD be good, as long as you don't try something crazy and try to renew a subclass. Since you said this is for a pool, it should be fine.
That said, my only question is - what is more legible? This is a question of taste, but imagine that somebody else might need to look at the code. You're basically just contracting two simple and obvious statements into one that requires deeper knowledge of what the code internally does.
In my pool functions, I typically had two separate methods, one to destroy and one to construct, both them essentially doing what you do here (p->~T and new(p) T()), but at least you know exactly what they did.
The delete() operator doesn't call the destructor of the object, which is unexpected to me.
I had to do a double take on new(p, ns::renew) foo(42). To me that's simply not intuitive.
What you probably really want is to seperate the process of allocating memory and the process of constructing objects. For situations like this, you typically use "placement new" instead.
// Not exception safe!
void* p = ::operator new(sizeof(T)); // allocate raw memory
new(p) T(41); // construct a T at this memory location
p->~T(); // destruct T
new(p) T(42); // recreate a different T at the same memory location
p->~T(); // destruct T
::operator delete(p); // deallocate raw memory
In a real memory pool application, you would wrap the above lines into a MemoryPool class of some sort.
Of course, this only applies if you're actually dealing with memory directly for the purpose of implementing an actual memory pool or an allocator of a container. In other situations, you're better off overloading the = operator() as suggested by Potatoswatter.