我有一个C ++库(包含50多个源文件),它使用了很多STL例程,主要容器是list和vector。这导致了巨大的代码膨胀,我想通过在列表和向量上创建一个包装器来减少代码膨胀。
下面显示的是我对std ::和包装实例的包装。
template<typename T>
class wlist
{
private:
std::list<T> m_list;
public:
// new iterator set.
typedef typename std::list<T>::iterator iterator;
typedef typename std::list<T>::const_iterator cIterator;
typedef typename std::list<T>::reverse_iterator reverse_iterator;
unsigned int size () { return m_list.size(); }
bool empty () { return m_list.empty(); }
void pop_back () { m_list.pop_back(); }
void pop_front () { m_list.pop_front(); }
void push_front (T& item) { m_list.push_front(item); }
void push_back (T item) { m_list.push_back(item); }
iterator insert(iterator position, T item) {m_list.insert(position,item);}
bool delete_item (T& item);
T back () { return (m_list.empty()) ? NULL : m_list.back();}
T front () { return (m_list.empty()) ? NULL : m_list.front();}
iterator erase(iterator item ) { return m_list.erase(item); }
iterator begin() { return m_list.begin(); }
iterator end() { return m_list.end(); }
reverse_iterator rbegin() { return m_list.rbegin(); }
};
档案A:
class label {
public:
int getPosition(void);
setPosition(int x);
private:
wlist<text*> _elementText; // used in place of list<text> _elementText;
}
档案B:
class image {
private:
void draw image() {
wlist<label*>::iterator currentElement = _elementText.begin();
((label*)(*currentElement))->getPosition();
currentElement ++;
}
}
我的信念是,通过包装STL容器,我可以减少代码膨胀,但代码大小的减少似乎是微不足道的,而我包装STL的动机是实现大约20%的代码减少。
1)通过暴露“包装”迭代器,我是否将嵌入的STL嵌入到我的客户端代码中,从而否定了我试图做的所有代码保存? 2)我选择了正确的分析方法????
修改前的尺寸:
$ size libWrap.so
text: 813115
data: 99436
bss: 132704
dec : 1045255
hex: ff307
修改后的尺寸:
$ size libWrap.so
text: 806607
data: 98780
bss: 132704
dec : 1038091
hex: fd70b
答案 0 :(得分:4)
首先,你的包装器提供的界面是完全和完全恶心的。迭代器存在是有原因的,这是因为你的实现平坦不适用于非指针类型。通过价值而不是通过参考来回归和接受?一个可怕的设计。
其次,您可以从不通过引入更多代码来减少程序的大小。您的包装器仍然使用引擎盖下的STL列表,因此您仍然要实例化所有这些类型。最有可能的是,编译器完全删除了整个批次。
第三,你甚至没有做同等的替换,因为你已经用指针列表替换了曾经是一个值列表,引入了六百万个终身头痛和其他问题。
第四,即使是代码膨胀的想法在绝大多数平台上都是非常荒谬的。当然,我不能在心理上知道你没有在几乎没有任何内存的某个嵌入式平台上工作(虽然我怀疑你会在这样的平台上使用很多列表)但是在几乎每个系统上,代码本身的大小都没有意义到程序执行所需的其他资产。
所做的是尝试使用SCARY迭代器或T *的部分特化。
答案 1 :(得分:1)
我想象一下为什么你关心这个。为什么这是一个问题?
我的猜测是你有很多(数百?)个不同的类,每个类都会生成模板化容器的副本。
如果是这样,如果有必要,那就坐下来让编译器为你做一些繁琐的工作。
如果没有必要,那么问题似乎可能是所有不同的类都没有必要。您的班级设计存在问题。您可能有许多不同的类,只是略有不同。如果差异很小,以至于为处理差异而生成的额外代码似乎不成比例,那么单个类中的代码可能会更好地处理不同的行为。
答案 2 :(得分:0)
似乎您只想在模板库中预编译模板化包装器,而不是让编译器在每次调用时都计算出模板化类。您可以通过将声明从头文件(通常用于模板化代码)移动到.cpp文件中来完成此操作。这还具有减少编译时间的优点。这种方法的灵活性是有代价的,但是,你从一开始就知道你希望你的类能够工作的类型(但是你不希望编译器为你找到它,无论如何)
将模板化代码放入.cpp文件通常会导致链接器错误。要避免这些,您需要明确声明希望编译器在cpp文件中编译的模板:
在.cpp文件的末尾,您可以编写类似
的内容template class wlist<double>;
template class wlist<int>;
等
这指示编译器编译器编译这些版本的类(并且只编译这些版本)。
这会降低库的灵活性 - 如果调用wlist<complex>
,则会出现链接器错误。
有关详细信息,请参阅此处:http://www.parashift.com/c++-faq-lite/templates.html#faq-35.12
我相信这通常是为了减少编译时间 - 我想它也会减少代码膨胀,但我从来没有使用过这种技术,因此从未检查过我的可执行文件的大小....