Using your own heap in place of new/malloc

This has got to be an old, old topic by now, so please forgive for bringing this up again.

I wish to dynamically allocate some structures with a project I'm (still) working on. Yes, I know I can just "new xxx" them and this is all handled nicely for me but I really, really want to ring fence the memory available for this activity to control and monitor its use.

Reading and googling about I believe I can (or could) just do something like this to create the object:

MyClass *ptr = (MyClass *)my_allocator( sizeof( MyClass ));
ptr->MyClass();

then this to release it:

ptr->~MyClass();
my_deallocator( (void *)ptr );

Which all makes logical sense to me: effectively just peeling away some of the C++ coating enough to allow me to fiddle about under the hood (yes, aware of potential alignment issues).

However I get the following error from the IDE's compiler: error: invalid use of 'MyClass::MyClass' with the call to the class constructor.

Can anyone spare a moment to point me towards the right explanation document? I seem to be stuck in a bit of a bubble, all the answers I can find seem to fail for various reasons. I'm starting to pull my hair out, and I haven't got that much to spare!

Cheers,
Jeff.

I wonder where you got that idea, because it does not seem to be correct.

It would help if you could provide links to your reference material, as well as a complete minimal example which shows your code.

Try a web search for "C++ placement new". But, it seem like more trouble than it's worth. You might just cause real problems while trying to solve the problem that doesn't exist.

2 Likes

I was never trained or used C++ (other than a trivial library in Arduino) but I created my own memory management code like that in standard C decades ago. I think you might be overthinking it.

This is how you can do what you are asking:

class myClass {
    int i;
};

int main () {
    // get enough memory, say from the heap
    void *p = malloc (sizeof (myClass));
    
    // create a new instance in the memory allocated
    myClass *q = new (p) myClass;
    
    // call instance destructor (do not use delete in this case since delete would also call free)
    q->~myClass ();

    // free the memory being used
    free (p);

    return 0;
}

Since q points to the exactly the same place as p you can use only one pointer instead of two in your code.

So ... I put this into the Arduino IDE:

class MyClass {
  private:
    int dummy;
  public:
    MyClass( void ) {
      dummy = 1;
    }
    ~MyClass() {
      dummy = 0;
    }
    int Called( void ) {
      return( dummy );
    }
};

void *memory( size_t size ) {
  return( malloc( size ));
}

void setup() {
  Serial.begin( 9600 );

  MyClass *ptr;

  ptr = new( memory( sizeof( MyClass ))) MyClass;

  Serial.print( ptr->Called());

  
}

void loop() {
  // put your main code here, to run repeatedly:

}

And try to compile it, I get this:

/home/jeff/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/avr-g++ -c -g -Os -Wall -Wextra -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -Wno-error=narrowing -MMD -flto -mmcu=atmega2560 -DF_CPU=16000000L -DARDUINO=10607 -DARDUINO_AVR_MEGA2560 -DARDUINO_ARCH_AVR -I/home/jeff/.arduino15/packages/arduino/hardware/avr/1.8.6/cores/arduino -I/home/jeff/.arduino15/packages/arduino/hardware/avr/1.8.6/variants/mega /home/jeff/.cache/arduino/sketches/7E3466A6CFA5C01F481E628463A906F1/sketch/sketch_feb16a.ino.cpp -o /home/jeff/.cache/arduino/sketches/7E3466A6CFA5C01F481E628463A906F1/sketch/sketch_feb16a.ino.cpp.o
/tmp/.arduinoIDE-unsaved2025116-96128-1961pf8.pk7q/sketch_feb16a/sketch_feb16a.ino: In function 'void setup()':
/tmp/.arduinoIDE-unsaved2025116-96128-1961pf8.pk7q/sketch_feb16a/sketch_feb16a.ino:26:42: error: no matching function for call to 'operator new(sizetype, void*)'
   ptr = new( memory( sizeof( MyClass ))) MyClass;
                                          ^~~~~~~
<built-in>: note: candidate: void* operator new(unsigned int)
<built-in>: note:   candidate expects 1 argument, 2 provided

exit status 1

Compilation error: no matching function for call to 'operator new(sizetype, void*)'

Yes, tried this already, hence my confusion.

The things I thought ought to work, and the things I've found (so far) which say they ought to work, don't. I don't think I'm being that silly - though it is always a possibility.

Jeff.

I have good reasons for wishing to directly manage the heap: memory is tight so I wish to statically allocate the heap space to enforce a hard limit on what's available. I'd rather the software has to manage an allocation failure than start allocating structures into the space required by the stack.

I'm still trying (to paraphrase an old saying) to get a quart into a pint pot. Literally every byte matters.

Jeff.

It seems that you are using an AVR board. I'm using ESP32 which uses C++ 201703 and the code compiles without a problem. Can you Serial.print __cplusplus to check C++ version you are using?

It seems that you have to include <new> on AVR :

#include <new>

class MyClass {
  private:
    int dummy;
  public:
    MyClass( void ) {
      dummy = 1;
    }
    ~MyClass() {
      dummy = 0;
    }
    int Called( void ) {
      return( dummy );
    }
};

void *memory( size_t size ) {
  return( malloc( size ));
}

void setup() {
  Serial.begin( 9600 );

  Serial.println (__cplusplus);

  MyClass *ptr;

  ptr = new (memory (sizeof (MyClass))) MyClass;

  Serial.println ( ptr->Called());
}

void loop() {
  // put your main code here, to run repeatedly:
}

Hi,

It prints out "201103".

I was beginning to think that perhaps I working under a false assumption about the compiler...

Jeff.

OK,

Twigged it. Penny dropped. Got that "D'Oh" moment.

Older compiler, simpler solution; just define replacement for operator new and operator delete.

We'll see how that goes with 20,000+ line of code - should be fine :slight_smile:

Thank you all,
Jeff.

Thank you - an almost throw away comment on a web page somewhere else said "if you're using something older than 17 you only need do this" (redefine the new and delete operators). As normal, once seeing the actual answer, it all seems so easy combined with a wave of "why didn't I see that before?".

It's either too late here or it's time I started thinking about another hobby.

Cheers,
Jeff.