【问题标题】:Reducing STL code bloat by wrapping containers通过包装容器减少 STL 代码膨胀
【发布时间】:2011-06-27 21:59:25
【问题描述】:

我有一个 C++ 库(包含 50 多个源文件),它使用大量 STL 例程,主要容器是列表和向量。这导致了巨大的代码膨胀,我想通过在列表和向量上创建一个包装器来减少代码膨胀。

下面显示的是我对 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

【问题讨论】:

  • 也许我遗漏了一些东西,但如果 wlist 最终拥有一个列表,这将如何减少代码膨胀?您仍然必须为 wlist 中使用的每种类型实例化一次列表模板。
  • @templatetypedef - 将公开一个非模板化的 wlist 类帮助???
  • @codebin- 它会,但是你会失去模板的所有好处(编译时类型安全、自动内联和优化等)这里没有灵丹妙药的解决方案 - 你是要么为你使用的模板付费,要么你不打算使用模板。您可以尝试减少您拥有的不同模板实例化的数量,但最终每个实例化都会影响代码大小。
  • 对于初学者,我会检查这是否真的是来自 STL 的代码膨胀 - 您是否在打开优化和关闭调试的情况下进行编译?其次,STL 本身会进行很多此类优化,因此您自己做的事情可能没有帮助。就像我说的 - 减少模板代码大小的唯一保证方法是使用更少的模板。如果你想缩小代码,然后找到你不需要 STL 容器的地方并用其他东西替换它。否则真的没有一个好的、可移植的方法来解决这个问题。
  • @codebin,使用函子和其他 stl 算法(例如for_each)。

标签: c++ list stl vector


【解决方案1】:

首先,您的包装器提供的界面完全令人作呕。存在迭代器是有原因的,这是因为您的实现完全不适用于非指针类型。按值而不是按引用返回和获取?糟糕的设计。

其次,您可以永远通过引入更多代码来减小程序的大小。您的包装器仍然在后台使用 STL 列表,因此您仍在实例化所有这些类型。很可能,编译器只是完全删除了所有内容。

第三,你甚至没有做等效的替换,因为你已经用指针列表替换了过去的值列表,带来了 600 万个终身头痛和其他问题。

第四,即使是代码膨胀的想法在绝大多数平台上都是相当荒谬的。当然,我从心理上无法知道您不是在几乎没有任何内存的嵌入式平台上工作(尽管我怀疑您会在这样的平台上使用很多列表),但在几乎每个系统上,代码本身的大小与它相比毫无意义到程序执行所需的其他资产。

可以做的就是尝试类似 SCARY 迭代器或 T* 的部分特化。

【讨论】:

  • 实际上,您可以通过引入更多代码来减少代码膨胀。您可以将vector 之类的类专门用于指针类型,并将实现隐藏在仅处理void* 的基类中。这允许仅在干净、类型安全的包装器中对所有(数据)指针类型和代码膨胀进行单一实现。
  • @Andre:这就是我在谈到部分指针特化时所指的。但是,我认为你误解了我的意思。专业化只改变一个类型,他们不引入它。但是,提问者的包装确实引入了新类型。
  • 我不确定我是否误解了这句话:“其次,您可以永远通过引入更多代码来减小程序的大小”。特化一个模板类引入更多代码。
  • @Andre Caron:是的,它引入了更多的文字源代码,但从编译器的角度来看,它实际上并不是更多的代码。实例化Wrapper&lt;T&gt; 仍然存在,就像之前一样,您只是命令编译器更改内容。
【解决方案2】:

我试图想象你为什么关心这个。为什么会有问题?

我的猜测是您有许多(数百个?)不同的类,每个类都会生成模板容器的副本。

如果是这样并且如果有必要,那么请坐下来让编译器为您完成繁琐的工作。

如果没有必要,那么问题似乎是所有不同的类都不是必需的。你的班级设计有问题。您可能有许多不同的类,它们之间的差别很小。如果差异如此之小以至于为处理差异而生成的额外代码似乎不成比例,那么不同的行为可能由单个类中的代码更好地处理。

【讨论】:

  • 有些人只是喜欢上 TheDailyWTF :)
【解决方案3】:

您似乎只想在库中预编译一次模板化包装器,而不是让编译器在每次调用模板类时都找出它。您可以通过将您的声明从头文件(通常用于模板化代码的位置)移动到您的 .cpp 文件中来做到这一点。这还具有减少编译时间的优点。这种方法的灵活性是有代价的,但是,您从一开始就知道您希望您的类适用于哪些类型(但无论如何您不希望编译器为您解决)

将模板化代码放入 .cpp 文件通常会导致链接器错误。为了避免这些,您需要明确声明您希望编译器在 cpp 文件中编译的模板:

在 .cpp 文件的末尾,您可以编写类似的内容

template class wlist<double>;
template class wlist<int>;

等等

这指示编译器编译这些版本的类(并且只编译这些版本)。 这当然会降低库的灵活性——如果你调用wlist&lt;complex&gt;,那么你会得到链接器错误。

查看这里了解更多信息:http://www.parashift.com/c++-faq-lite/templates.html#faq-35.12

我相信这样做通常是为了减少编译时间 - 我想它也会减少代码膨胀,但我从未使用过该技术,因此从未检查过我的可执行文件的大小....

【讨论】:

  • 我真的不确定他要什么。 “代码膨胀”通常意味着从二进制文件中删除一些不必要的生成代码,但模板不会添加任何不必要的代码。编译器已经只实例化了所需的模板。您的技术使编译器运行得更快,但最终,被实例化的模板完全一样。
  • @Deong - 谢谢,我认为可能是这种情况......我不得不承认我对编译器“实际上做了什么”知之甚少。
猜你喜欢
  • 1970-01-01
  • 2011-03-03
  • 2011-02-03
  • 1970-01-01
  • 2014-03-24
  • 1970-01-01
  • 2019-10-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多