0

I'm trying to make my own memory allocator in C++ for educational purposes, and I have a code like this:

class IntObj
{
public:
    IntObj(): var_int(6) {}

void setVar(int var)
{
    var_int = var;
}

int getVar()
{
    return var_int;
}

virtual size_t getMemorySize()
{
    return sizeof(*this);
}
int a = 8;

~IntObj()
{}
private:
    int var_int;
};

And I'm stuck with how to have unused memory chunks merge. I'm trying to test it like this:

char *pz = new char[sizeof(IntObj) * 2]; //In MacOS, IntObj takes 16 bytes
char *pz2 = &pz[sizeof(IntObj)]; // Take address of 16-th cell
char *pz3 = new char[sizeof(IntObj) / 2]; //Array of 8 bytes

char **pzz = &pz2; 
pzz[sizeof(IntObj)] = pz3; // Set address of cell 16 to the pz3 array
new (&pzz) IntObj; //placement new

IntObj *ss = reinterpret_cast<IntObj *>(&pzz);
cout << ss->a;

The output is 8 as expected. My questions:

  • Why the output is correct?
  • Is the code like this correct? If not, are there any other ways to implement coalescence of two memory chunks?

UPDATE: All methods work correctly. e.g this would work:

ss->setVar(54);
cout << ss->getVar();

The output is 54.

UPDATE 2: First of all, my task is not to request a new memory block from OS for instantiating an object, but to give it from a linked list of free blocks(that were allocated when starting a program). My problem is that I can have polymorphic objects with different sizes, and don't know how to split memory blocks, or merge (that is what I understand by merging or coalescing chunks) them (if allocation is requested) effectively.

  • if you could be more clear about what you intend by "merging chunks" I can better improve my answer with possible suggestions – kmdreko Jun 10 '18 at 10:39
  • @vu1p3n0x First of all, my task is not to request a new memory block from OS for instantiating an object, but to give it from a linked list of free blocks(that were allocated when starting a program). My problem is that I can have polymorphic objects with different sizes, and don't know how to split memory blocks, or merge (that is what I understand by merging or coalescing chunks) them (if allocation is requested) effectively. – Andrew Raiden Jun 10 '18 at 10:54
  • Unfortunately, c++ objects cannot straddle different blocks of memory (without a pointer to them, but then as far as c++ is concerned, they're different objects). Fortunately though, objects don't change size, and you know the size when allocated, so it sounds like what you'd want is a [custom allocator](https://stackoverflow.com/questions/826569/compelling-examples-of-custom-c-allocators). (also your use of `pz2` is a way you can "split" memory chunks, just make sure you keep track of them) – kmdreko Jun 10 '18 at 11:19

1 Answers1

3

There's a number of misunderstandings apparent here

char *pz = new char[sizeof(IntObj) * 2];  // fine
char *pz2 = &pz[sizeof(IntObj)];          // fine
char *pz3 = new char[sizeof(IntObj) / 2]; // fine
char **pzz = &pz2;                        // fine
pzz[sizeof(IntObj)] = pz3;                // bad

pzz is a pointer that is pointing to only a single char*, which is the variable pz2. Meaning that any access or modification past pzz[0] is undefined behavior (very bad). You're likely modifying the contents of some other variable.

new (&pzz) IntObj; // questionable

This is constructing an IntObj in the space of the variable pzz, not where pzz is pointing to. The constructor of course sets a to 8 thereby stomping on the contents of pzz (it won't be pointing to pz2 anymore). I'm uncertain if this in-and-of-itself is undefined behavior (since there would be room for a whole IntObj), but using it certainly is:

IntObj *ss = reinterpret_cast<IntObj *>(&pzz); // bad

This violates the strict-aliasing rule. While the standard is generous for char* aliases, it does not allow char** to IntObj* aliases. This exhibits more undefined behavior.

If your question comes down to whether or not you can use two independent and contiguous blocks of memory as a single block then no, you cannot.

kmdreko
  • 42,554
  • 6
  • 57
  • 106
  • For late readers, this is a correct observation. You can however coalesce memory, although it's pretty advanced. Look into unions, blobs, usage of void pointers, copying memory, etc. It can be done and is actually done pretty frequently at low-level programming. – Attersson Jun 10 '18 at 11:22
  • (in response to poster comment about allocation requesting elaboration) Sure there are plenty ways. In case of continuous memory, values can be swapped without allocation (id est a^=b b^=a a^=b) and made adjacent for merging. Some encoding can be used to store lengths information. As for linked lists, we talk about different chunks of memory so merging means accessing both. Objects can be made, for instance instead of an array of 8 ints, 2 arrays of 4 ints with custom operations that handle atomic writing, etc etc, everything is possible. – Attersson Jun 10 '18 at 11:35
  • @Attersson certainly all those options are available, but all would require heavy modification of classes stored in such systems. I took the question more at face value: "how can I use two chunks of memory as one contiguous chunk?" (you cannot) – kmdreko Jun 10 '18 at 11:40
  • Definitely makes sense. Since StackOverflow is often googled this sorts of "dialectic" comments have to be made in order to offer as much and as complete information as possible – Attersson Jun 10 '18 at 11:43