mardi 19 décembre 2017

How to avoid C++ code bloat issued by template instantiation and symbol table?

I'd started a bare-metal (Cortex-M) project some years ago. At project setup we decided to use gcc toolchain with C++11 / C++14 etc. enabled and even for using C++ exceptions and rtti.

We are currently using gcc 4.9 from http://ift.tt/2kHif0l (having some issue which prevent us currently to update to a more recent gcc version).

For example, I'd wrote a base class and a derived class like this (see also running example here):

class OutStream {
public:
    explicit OutStream() {}
    virtual ~OutStream() {}
    OutStream& operator << (const char* s) {
        write(s, strlen(s));
        return *this;
    }
    virtual void write(const void* buffer, size_t size) = 0;    
};

class FixedMemoryStream: public OutStream {
public:
    explicit FixedMemoryStream(void* memBuffer, size_t memBufferSize): memBuffer(memBuffer), memBufferSize(memBufferSize) {}
    virtual ~FixedMemoryStream()       {}
    const void*  getBuffer() const     { return memBuffer; }
    size_t       getBufferSize() const { return memBufferSize; }
    const char*  getText() const       { return reinterpret_cast<const char*>(memBuffer); }  ///< returns content as zero terminated C-string    
    size_t       getSize() const       { return index; }                                     ///< number of bytes really written to the buffer (max = buffersize-1)
    bool         isOverflow() const    { return overflow; }
    virtual void write(const void* buffer, size_t size) override { /* ... */ }
private:
    void*  memBuffer = nullptr;   ///< buffer
    size_t memBufferSize = 0;     ///< buffer size
    size_t index = 0;             ///< current write index
    bool   overflow = false;      ///< flag if we are overflown
};

So that the customers of my class are now able to use e.g.:

char buffer[10];
FixedMemoryStream ms1(buffer, sizeof(buffer));
ms1 << "Hello World";

Now I'd want to make the usage of the class a bit more comfortable and introduced the following template:

template<size_t bufferSize> class FixedMemoryStreamWithBuffer: public FixedMemoryStream {
public:
    explicit FixedMemoryStreamWithBuffer(): FixedMemoryStream(buffer, bufferSize) {}
private:
    uint8_t buffer[bufferSize];
};

And from now, my customers can write:

FixedMemoryStreamWithBuffer<10> ms2;
ms2 << "Hello World";

But from now, I'd observed increasing size of my executable binary. It seems that gcc added symbol information for each different template instantiation of FixedMemoryStreamWithBuffer (because we are using rtti for some reason).

Might there be a way to get rid of symbol information only for some specific classes / templates / template instantiations?

It's ok to get a non portable gcc only solution for this.

For some reason we decided to prefer templates instead of preprocessor macros, I want to avoid a preprocessor solution.

Aucun commentaire:

Enregistrer un commentaire