Reason for missing new() / delete()?

Hi,
Can anyone give me a concise reason that Arduino is missing new() and delete()?

I am finding that I need to jump through hoops to create static methods to do some things, because I can't allocate C++ classes... I need to use malloc() on some data structures.

After having done so, I can only think... "Geez, I wish I had new()".

BTW, I know that there is a new() operator implementation out there such that I can define it myself and I plan to use it... barring a good "Only n00bs use new(), that's why it's left out of the Arduino C++ stuff" explanation.

Thanks.

As you know, no doubt, you can get new and delete by adding these lines to your project:

// new
void * operator new (size_t size) { return malloc (size); }
// placement new
void * operator new (size_t size, void * ptr) { return ptr; }
// delete
void operator delete (void * ptr) { free (ptr); }

Now, why they aren't in the standard implementation is a bit of mystery. Perhaps "they" are trying to discourage dynamic memory allocation. Well in that case, why supply malloc and free?

Sure, dynamic memory allocation can be misused. But then, can't you say that about anything?

The ugly hoops you run through to create static objects (class instances) without using new is surely worse than allocating a handful of things dynamically in setup?

In fact, encouraging users to make static objects is encouraging the "static initialization order fiasco" problem - a well-known issue caused by creating static class instances. I don't know why you would encourage that.

http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.15

And no, it is not only n00bs that use new. Its use is so widespread that I think you could even say "only n00bs would not use new".

Thanks, Nick. I feel better about feeling bad about not having new(), and wanting to implement it in apparent violation of the wishes of the IDE developers.

As a matter of fact, what the developers of the PinChangeInt library did was allocate space ahead of time, by defining an array of objects:

static PCintPin pinDataAlloc[MAX_PIN_CHANGE_PINS];

...developers who use this library need to poke around in the .h files to discover what MAX_PIN_CHANGE_PINS does, and set it appropriately. If one neglects to do so, and leaves MAX_PIN_CHANGE_PINS at its default of 8, then if you use this library to catch interrupts on 1 pin, space is allocated for 7 extra PCintPin objects that you won't use. And I, creating a library that uses this library, now have to expose gory details to the developer when I'd rather they have a nice easy interface.

I'd much rather use a dynamically-created linked list and have it grow as large or as small as I need. But I preach to the choir. In short: thanks. I'm going to use new() guilt-free. 8)

BTW, according to this article: Implementing New and Delete C++ Functionality for Arduino which points more importantly to this discussion: http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=410870, the new() operator can be a little more involved

because if you are using gcc 4.x and newer (I didn't check it with older versions) and you want to use templates, virtual inheritance and so on you must define some additional functions, which is not used now by compiler, but must be present to satisfy linker

So the final code should look like:

#ifndef cppfix
#define cppfix

#include <stdlib.h>

__extension__ typedef int __guard __attribute__((mode (__DI__)));

void * operator new(size_t size);
void operator delete(void * ptr);

int __cxa_guard_acquire(__guard *g) {return !*(char *)(g);};
void __cxa_guard_release (__guard *g) {*(char *)g = 1;};
void __cxa_guard_abort (__guard *) {};

void * operator new(size_t size)
{
return malloc(size);
}

void operator delete(void * ptr)
{
free(ptr);
}

#endif

Can anyone give me a concise reason that Arduino is missing new() and delete()?

Because in a RAM-constrained embedded environment, you shouldn't be using them.
(Contentious, or what?)

AWOL:

Can anyone give me a concise reason that Arduino is missing new() and delete()?

Because in a RAM-constrained embedded environment, you shouldn't be using them.
(Contentious, or what?)

That's what I thought. But then one ends up with this:static PCintPin pinDataAlloc[MAX_PIN_CHANGE_PINS]; as I mention above. If I create a library which depends on the other library, and I essentially hide the details of the other library, now I've got an issue because the developer who uses my library has to deal with implementation-specific details, such as the fact that if they don't understand the library that I'm using, they won't know to change MAX_PIN_CHANGE_PINS. So they'll either A) be wasting the very RAM that our new()-less environment was supposed to conserve, or B) end up with a weird bug.

Indeed, in my AdaEncoder library, I dealt with the absence of new() by creating a linked list of structures using malloc(). And when all was said and done, I said to myself, "Damn, all this malarkey I had to go through to use malloc() in a C-stylin' kind of way, rather than just using new(). And did it avail me anything? I mean, what's the big difference between a struct and a class anyway? According to Stroustroup, a class is essentially a struct..."

...Of course, this is the very contention you're alluding to. :stuck_out_tongue:

New and delete are annoyingly coupled to do two things: They allow you to allocate and release "dynamic" memory, and they allow you to construct and destroy objects.

You can work around this: "placement new" allows you to use memory you already have to construct an object, and "destructor call" allows you to destroy an object without passing the memory to operator delete.

// declaration of placement new:
inline void *operator new(size_t, void *buf) { return buf; }

// use of placement new:

char buf[sizeof(SomeClass)];

SomeClass *maker_func() {
  // initialize a SomeClass in the given buffer
  new(buf) SomeClass(args);
}

void destroyer_func(SomeClass *sc) {
  // destroy the SomeClass without handing the memory to free()
  sc->~SomeClass();
}

In an embedded system, you always have to know the upper limit on whatever it is you're trying to do, and you have to enforce that limit somehow. The "softer" behavior of traditional new and delete aren't usually applicable, so I prefer to use fixed buffers and placement new.

Now, if you want a helper library that uses some configurable number of objects, that can still be fixed at compile time, using non-type template arguments.

// declaration of class
template<size_t NumPins> class PinUser {
public:
  PinUser() { ... };
  void method() { ... }
  static PinUser ByIndex[NumPins];
};

// use of class
#include <PinUser.h>
PinUser<2> Pins;

// invocation of methods
Pins::ByIndex[1].method();

The fact that the library you're talking about is constructed without this mechanism makes it harder to discover and control, as you state. However, some people feel that templates are hard to work with or use, so that method of library construction is probably not going away.
At least there are options :slight_smile:

GreyGnome:

because if you are using gcc 4.x and newer (I didn't check it with older versions) and you want to use templates, virtual inheritance and so on you must define some additional functions, which is not used now by compiler, but must be present to satisfy linker

Actually that is required for something different, not dynamic memory allocation, as this demonstrates:

class foo
  {
  public:
  foo () { bar = 0; }
  int bar;
  };
  
void setup ()
{
 static foo x;
}

void loop () {}

Compiling this:

sketch_oct04a.cpp.o: In function `setup':
sketch_oct04a.cpp:13: undefined reference to `__cxa_guard_acquire'
sketch_oct04a.cpp:13: undefined reference to `__cxa_guard_release'

No new or delete there. Just a statically-allocated class member inside a function.


AWOL:
Because in a RAM-constrained embedded environment, you shouldn't be using them.

If you are short of RAM, careful memory management is certainly required. However avoiding dynamic memory allocation is not necessarily that.

Just to give a couple of examples ...

Try this sketch on a Mega2560:

void setup ()
{
Serial.begin (115200);
Serial.print (sizeof (Serial1));
}

void loop () {}

That prints "19". So, 19 bytes used up for Serial1. In fact, without asking if you need them or not, you get Serial, Serial1, Serial2, and Serial3:

#if defined(UBRRH) || defined(UBRR0H)
  extern HardwareSerial Serial;
#elif defined(USBCON)
  #include "usb_api.h"
#endif
#if defined(UBRR1H)
  extern HardwareSerial Serial1;
#endif
#if defined(UBRR2H)
  extern HardwareSerial Serial2;
#endif
#if defined(UBRR3H)
  extern HardwareSerial Serial3;
#endif

That's 76 bytes gone, when memory is short, and you might only need 19. Perhaps you should dynamically allocate Serial1, Serial2, and Serial3? Then you get them only if you need them.

Now look at the Wire (I2C) library. Internally that has 5 x statically-allocated buffers of 32 bytes each. That's 160 bytes in total. Out of only 2048 available on a Atmega328. Too bad if you need that memory for something else. Too bad if you need 40 byte buffers, you don't get a chance to change that 32-byte limit (short of editing the library code). Too bad if you only need 10 byte buffers.

If you only need 10 byte buffers, 5 of them would only be 50 bytes, compared to 160 bytes. So this static allocation doesn't seem to me, on the face of it, to be saving memory. It forces designers to design for the "common case" which means they allocate too much static memory for some cases, and too little for others. All this could be fixed by using dynamic allocation.

Now of course, dynamic allocation can be abused. Anything can be abused. People make recursive function calls when they shouldn't. They run off the end of buffers. They use variables without initializing them. Getting it right is part of the job. But you don't just remove something because it can be abused.

Probably the worst offender is the String library, not because it is bad per se, but because if you build up strings a byte at a time (eg. concatentating when reading from the serial port) you get major memory fragmentation. So yes, that isn't a good idea.

Early PCs (eg. the original Macintosh) used dynamic memory allocation. Not because they had a lot of memory. Because they were short of memory, and had to use it as cleverly as they could.

The sense I get is that if you're writing a library, you should use malloc/free (and in fact, you may have to, since new/delete are gone). If you're writing a sketch for a particular purpose (i.e., the majority of Arduino developers), you should use singleton variables or fixed-size arrays, and not malloc/free/new/delete.

I'm not saying I agree with the decision to remove new/delete - but I can see that at least it makes you pause before going forward.

I've no objections to using malloc or new in setup() if the amount of memory needed can't be determined at compile time; but using free or delete risks memory fragmentation. As a general rule, I only allocate memory dynamically where static allocation is unsuitable, and I never free memory once I have allocated it. A classic example would be in a library function where the size of a buffer or the number of devices or pins controlled is user-specified in a 'begin' call.

Also bear in mind that when you use malloc or new, there is a memory overhead of a few bytes for each block or object you allocate.

I don't have a Mega, so I can't verify this. But, as those are individual, extern symbols, defined in a library, it's quite possible that the linker will be smart enough to not include the symbols you're not using.
Then again, it's also quite possible that the good-old "include everything if you use anything" behavior of the traditional GNU linker has carried over to the Arduino environment.

(I just lied to the IDE and told it I had a Mega, and checked the ELF file with objdump, and it does include all four. Unfortunate!)

00800422 <Serial>:
	...

00800435 <Serial1>:
	...

00800448 <Serial2>:
	...

0080045b <Serial3>:
	...

AndyCC:
The sense I get is that if you're writing a library, you should use malloc/free (and in fact, you may have to, since new/delete are gone). If you're writing a sketch for a particular purpose (i.e., the majority of Arduino developers), you should use singleton variables or fixed-size arrays, and not malloc/free/new/delete.

Well said! I think this sums it up nicely, and reflects my conundrum. I'm writing a library, so I have the need to use dynamic memory (and to use a new/delete provided on the Internet).

If I was writing a sketch for something static, then yes I may prefer to use fixed-size arrays.

I don't see what is stopping you adding the three lines I posted further up, into a separate new.cpp file in your library. That makes it work, and if one day they put new and delete in the main distribution just omit that file. And have notes to that effect in the readme.txt file.