18

I'm new to C++ programming, but have been working in C and Java for a long time. I'm trying to do an interface-like hierarchy in some serial protocol I'm working on, and keep getting the error:

Undefined reference to 'operator delete(void*)'

The (simplified) code follows below:

PacketWriter.h:

class PacketWriter {
public:
    virtual ~PacketWriter() {}
    virtual uint8_t nextByte() = 0;
}

StringWriter.h:

class StringWriter : public PacketWriter {
public:
    StringWriter(const char* message);
    virtual uint8_t nextByte();
}

The constructor and nextByte functions are implemented in StringWriter.cpp, but nothing else. I need to be able to delete a StringWriter from a pointer to a PacketWriter, and i've been getting various other similar errors if I define a destructor for StringWriter, virtual or not. I'm sure it's a simple issue that I'm overlooking as a newbie.

Also, I'm writing this for an AVR chip, using avr-g++ on Windows.

Thanks

Vinicius Kamakura
  • 7,299
  • 1
  • 25
  • 42
Bracket
  • 362
  • 1
  • 2
  • 9
  • 8
    How do you run the compiler ? If you use `avr-gcc` or something like that, then you should rather use `avr-g++` or equivalent. – Alexandre C. Aug 10 '11 at 17:43
  • Are you sure the error is related to the code you are showing here? – sth Aug 10 '11 at 17:43
  • 1
    Are you linking this in a peculiar way? If you link against the usual runtime, implementations of `operator new` and `operator delete` are provided, but if you do something bareback you may need to define those yourself. – Kerrek SB Aug 10 '11 at 17:45
  • 2
    This error would occur if you didn't link the C++ standard libraries into the final executable. Are you linking this in? – templatetypedef Aug 10 '11 at 17:45
  • We are not telepathic. Give us some code that we can compile and get the same results (an error) as you. Then we can tell you what the answer is. – Martin York Aug 10 '11 at 17:51
  • 4
    I am pretty sure new/delete are not being implemented, and for a good reason, it is an embedded system. Read the documentation properly. – Vinicius Kamakura Aug 10 '11 at 17:53
  • 1
    @hexa: good catch: http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_cplusplus . You can probably post this as an answer – Alexandre C. Aug 10 '11 at 17:55
  • @Bracket I can see you plan on wrapping malloc/free into new/delete. Please read about memory fragmentation, it is CRITICAL in an embedded environment, or do you think people from AVR simply forgot to implement new and delete? They have a very good reason. Start here: http://stackoverflow.com/questions/3770457/what-is-memory-fragmentation/3770593#3770593 – Vinicius Kamakura Aug 10 '11 at 18:14
  • I hadn't thought about fragmentation. I am only ever allocating at most two things on the heap at any time. They both persist for the duration of a serial transaction before getting deleted. I've got 4k of RAM and the largest objects I would allocate are 18 bytes, so I don't think it will cause any problems. – Bracket Aug 10 '11 at 18:34
  • Funny, a commercial production software behaves like that in some conditions: libmemcached. `clients/clients_memcapable-memcapable.o: In function `std::__1::allocator::deallocate(char**, unsigned long)': /usr/include/c++/v1/memory:1632: undefined reference to `operator delete(void*)'` – Dereckson Apr 29 '15 at 12:35

4 Answers4

35

Sorry for posting in an old thread, but it's still pretty high in Google's search results and if you have this problem, you really should check out this link, because there it says that you simply need to link -lstdc++ and this is what solved the problem for me.

The following line was added by the Community without highlighting it as such and instead of just adding a comment to my answer for reasons that elude me: "Or use a C++ compiler that will implicitly add the -lstdc++ option, e.g. g++."

Alex
  • 1,028
  • 1
  • 12
  • 23
  • 2
    FYI. Linking in stdc++ doesn't necessarily fix this issue. I am using -lstdc++ and tried g++ as well, but still see this issue. – matt snider Jul 06 '16 at 23:27
  • 3
    I have been banging my head against a wall for several weeks now trying to figure out why my CUDA code would not run properly. I tried everything I could possibly find. Your comment fixed everything, saved the day, solved my life, and I love you so much. Thank you thank you thank you thank you!!!!! – boof Feb 22 '17 at 06:22
  • 1
    make sure -lstdc++ goes "after" FWIW – rogerdpack Feb 23 '18 at 21:38
  • 1
    Solved my problem magically .Thank you! For later readers' reference: I am trying to link a C++ library called libzmq from my embedded Linux C code. If I use a C++ compiler everything is fine, but if I have to use a C compiler for some reason. Then I see all those undefined errors. Adding `-lstdc++` solves the problem. – Penghe Geng Oct 10 '18 at 19:30
15

If you are not linking against the standard library for some reason (as may well be the case in an embedded scenario), you have to provide your own operators new and delete. In the simplest case, you could simply wrap malloc, or allocate memory from your own favourite source:

void * operator new(std::size_t n)
{
  void * const p = std::malloc(n);
  // handle p == 0
  return p;
}

void operator delete(void * p) // or delete(void *, std::size_t)
{
  std::free(p);
}

You should never have to do this if you are compiling for an ordinary, hosted platform, so if you do need to do this, you better be familiar with the intricacies of memory management on your platform.

Kerrek SB
  • 428,875
  • 83
  • 813
  • 1,025
  • It seems that there is no standard library support for this chip: http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_cplusplus . The behaviour of new and delete that the OP observes is even documented. – Alexandre C. Aug 10 '11 at 17:57
  • I know there are implementations of malloc and free for the AVR in C. If I just wrap those up once somewhere, will they work for all objects? Where would I put that code? – Bracket Aug 10 '11 at 18:06
  • You put the code just anywhere in the global namespace and link against it. If you don't want `malloc`, you could also allocate memory from some pool area and maintain a free list or something like that. – Kerrek SB Aug 10 '11 at 18:08
  • Okay, that seems to work (or at least compile without error :P). Thanks! – Bracket Aug 10 '11 at 18:14
  • Cool, but do beware, you really have to know what you're doing and where you're getting your memory from. I think `malloc` is a very dangerous beast in the embedded world, but I'm not an expert by a long shot. – Kerrek SB Aug 10 '11 at 18:15
  • It is a beast I have fought with before, but never in C++. I'm keeping a close watch over everything that gets allocated to make sure it gets deleted later. – Bracket Aug 10 '11 at 18:23
10

I will just quote the documentation, since they put it better.

Writing C++

You can write programs for the AVR platform in C++, if you included c++ in the enabled-languages during configuration of avr-gcc. Just about everything in the Writing C AVR programs section applies, so read that first.

The major drawbacks of using C++ are:

C++ calling convention side-effects
No libstdc++ support.

C++ calling convention side-effects

Certain C++ features will automatically generate implied code if required, which can waste valuable program memory space and processor time. For instance, if at some point in the program a function is passed a C++ object by value:

void myfunction(MyCppClass object);

You will wind up with a default copy constructor being generated and called to create the temporary copy of object used in myfunction(). Be careful if this isn't what you want: equivalent behavior should be attainable by passing a reference to a constant MyCppClass object, while avoiding the code and execution overhead.

Missing libstdc++ and other C++ features

None of the C++ standard templates, classes or functions are available. In addition, operators new and delete have yet to be implemented.

C++ exception support is also lacking. You'll probably need to make sure to use the -fno-exceptions compiler option to turn off the exceptions in the C++ front-end.

What does work? Even though lots of the C++ goodies you are accustomed to working with aren't available, it can be worthwhile to program the AVR in C++. Constructors and destructors are functional and just the organizational advantages of using classes and object oriented programming may make C++ a great choice.

Vinicius Kamakura
  • 7,299
  • 1
  • 25
  • 42
  • 1
    i will add that "The operators new and delete are not implemented, attempting to use them will cause the linker to complain about undefined external references. (This could perhaps be fixed.)" – user3125280 Jan 18 '14 at 16:59
5

If you're just looking to do an interface, you don't need new/delete. Just remove the "virtual" from the base class destructor, and make sure the derived class has an implementation of __cxa_pure_virtual().

Here is a compilable example. (I removed the returns to keep things simple, but it works just fine with them.)

In PacketWriter.h

class PacketWriter {
public:
    virtual void nextByte() = 0;
protected:
    ~PacketWriter() {}
};

In StringWriter.h

#include "PacketWriter.h"

class StringWriter : public PacketWriter {
public:
    StringWriter(const char* message);
    void nextByte();
};  

In StringWriter.cpp

#include "StringWriter.h"

// Definition of the error function to call if the constructor goes bonkers
extern "C" void __cxa_pure_virtual() { while (1); }

StringWriter::StringWriter(const char* message)
{
    // constructor code here
}

void StringWriter::nextByte()
{
}

Compile with avr-g++ StringWriter.cpp

MikeTwo
  • 904
  • 1
  • 12
  • 9