我们目前正在使用gcc 4.9 from launchpad.net/gcc-arm-embedded(有一些问题阻止我们目前更新到更新的gcc版本)。
例如,我写了一个基类和这样的派生类(另请参见运行示例here):
12
因此,我班级的客户现在可以使用例如:
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
};
现在我想让这个类的使用更加舒适,并介绍了以下模板:
char buffer[10];
FixedMemoryStream ms1(buffer, sizeof(buffer));
ms1 << "Hello World";
从现在开始,我的客户可以写下:
template<size_t bufferSize> class FixedMemoryStreamWithBuffer: public FixedMemoryStream {
public:
explicit FixedMemoryStreamWithBuffer(): FixedMemoryStream(buffer, bufferSize) {}
private:
uint8_t buffer[bufferSize];
};
但从现在开始,我发现可执行二进制文件的大小越来越大。似乎gcc为FixedMemoryStreamWithBuffer<10> ms2;
ms2 << "Hello World";
的每个不同模板实例化添加了符号信息(因为我们出于某种原因使用了rtti)。
可能有办法仅针对某些特定的类/模板/模板实例来删除符号信息吗?
可以为此获得非便携式gcc解决方案。
出于某种原因,我们决定更喜欢模板而不是预处理器宏,我想避免使用预处理器解决方案。
答案 0 :(得分:2)
是的,有一种方法可以将必要的符号几乎降到0
:使用标准库。您的OutStream
课程是std::basic_ostream
的简化版。您的OutStream::write
实际上只是std::basic_ostream::write
,依此类推。看看它here。然而,溢出处理非常紧密,为了完整起见,它还处理underflow
,即需要数据检索;您可以将其保留为未定义(它也是virtual
)。
同样,您的FixedMemoryStream
为std::basic_streambuf<T>
,其中包含固定大小(std::array<T>
)的获取/投放区域。
所以,只要让你的类继承自标准的类,你就会切断二进制大小,因为你正在重用已经声明的符号。
现在,关于template<size_t bufferSize> class FixedMemoryStreamWithBuffer
。此类与std::array<std::uint8_t, bufferSize>
非常类似于指定和获取内存的方式。你无法对此进行优化:每个实例都是不同的类型,包含所有含义。编译器不能“合并”或对它们做任何魔术:每个实例化必须有自己的类型。
因此,要么退回到std::vector
,要么有一些固定大小的专用块,如32,128等,并且对于中间的任何值都会选择正确的块;这可以完全在编译时实现,因此没有运行时成本。
答案 1 :(得分:2)
首先,请记住,编译器还为每个FixedMemoryStreamWithBuffer&lt;&gt;生成单独的v表(以及RTTI信息)。类型实例,以及继承链中的每个类。
为了解决这个问题,我建议在内部使用一些转换函数和/或运算符来使用包含而不是继承:
template<size_t bufferSize>
class FixedMemoryStreamWithBuffer
{
uint8_t buffer[bufferSize];
FixedMemoryStream m_stream;
public:
explicit FixedMemoryStreamWithBuffer() : m_stream(m_buffer, bufferSize) {}
operator FixedMemoryStream&() { return m_stream; }
FixedMemoryStream& toStream() { return m_stream; }
};