C/C++编程:模板的代码膨胀问题

1060 篇文章 295 订阅

模板的另一个重要缺点是其所带来的**代码膨胀**。代码膨胀可以分为两种情况:

  • 源代码的增加
  • 编译生成目标代码尺寸的增加


源代码的增加


虽然模板大大增加了代码的复用性,同时也降低了代码总量。但是,有时需要为同一模板提供不同情景下的不同实现,也就是模板特例机制。

但是,C++的模板特例机制有很大的局限性,就是特例必须以函数或者类为单位整体生成,对于模板特例只需要根据模板参数值答对小部分代码块进行微调的情况,就会生成重复代码。


目标代码的增加


会在每一次编译过程中,产生越来越大的文件尺寸,耗费越来越长的编译时间。

造成代码膨胀的主要原因:

  • 模板实例在多个目标文件中重复存在(如今大部分编译器会在链接时删除重复的函数模板实例)
  • 模板机制所导致的大量实例以及相关的函数模板实例的出现


关于第2点的例子:

template<typename T, typename N>
struct node{
  //***
};
typename node<int, void>node1;
typename node<int, node1> node2;
typename node<int, node2> node3;


使用上面模板时,没增加一个节点就会新增一种类型,以致编译器不停的构造新类型以生成新类型的函数模板实例,从而增加模板文件尺寸。

怎么解决


模板虽好,不要滥用。

所谓合理利用模板,有两层含义:

  • 预估模板可能生成类型的数量级。对于能自动生成新模板示例的函数模板,一定要慎重考虑其使用频度,防止新类型泛滥。
  • 最大限度的降低与模板参数有关的操作量。因为每当从某类函数生成新的实例类型时,与其相关联的被调用到的函数模板也都会生成新的函数实例,增加真实的目标代码量

对于第二点,技巧如下:

  • 当我们设计类模板时,很自然的将其所有的成员函数都在类模板内实现。这样,所有成员函数都为函数模板。每当类模板生成新实例时,其成员函数都有可能相应的生产新的模板实例。
  • 但是如果仔细分析,会发现不会所有的成员函数的操作都与新类型有关,有些类型无关的操作,完全不必写成模板。如能将这些操作提取出来,就可以成比例的降低函数模板所生成的目标代码量,从而显著减少目标文件尺寸和编译时间
  • 那么该怎么提取呢?具体做法是为目标设计一个与模板参数无关的基类,再将模板类中与模板参数无关的成员变量以及函数都提升到基类中实现。这样,各个类模板实例所调用的都是共同基类中的成员函数,就不会重复生成等价的函数实例。

看个例子:

#include <cstddef>

struct list_node_base{
    list_node_base* next;
    list_node_base* prev;
    list_node_base(list_node_base *next = 0,
            list_node_base *prev = 0):
            next(next), prev(prev){}
};

template <typename T>
struct list_node : list_node_base{
    typedef T value_type;
    T value;
    list_node(T const&value,
            list_node_base * next = 0,
            list_node_base * prev = 0) :
            list_node_base(next, prev),
            value(value){}
};

template <typename T> class list; // 前置声明

template <typename T>
class list_iterator :public std::iterator<std::bidirectional_iterator_tag, T>{
    list_node_base *pos;
    typedef std::iterator<std::bidirectional_iterator_tag, T> base_type;
public:
    list_iterator(list_node<T> *pos) : pos(pos) {}
    list_iterator() : pos() {}

    list_iterator&operator++() {pos = pos->next;}
    list_iterator&operator--() {pos = pos->prev;}
    bool operator==(list_iterator const &right){ return pos == right.pos;}
    bool operator!=(list_iterator const &right){ return pos != right.pos;}

    typename base_type::reference
    operator*() { return static_cast<list_node<T>*>(pos)->value;}

    friend class list<T>;
};

class list_base{
protected:
    list_node_base *head;
    list_node_base *tail;
    size_t  sz;

    void push_back_only(list_node_base * pos){
        if(tail){
            tail->next = pos;
            pos->prev = tail;
            tail = pos;
        }else{
            tail = pos;
            head = pos;
            pos->prev = 0;
            pos->next = 0;
        }
    }

    void pop_back_only(){
        if(tail){
            list_node_base *p = tail;
            tail = tail->prev;
            delete p;
        }
    }

    void swap(list_base &r){
        std::swap(head, r.head);
        std::swap(tail, r.tail);
        std::swap(sz, r.sz);
    }

public:
    typedef size_t size_type;

    list_base() : head(0), tail(0), sz(0){}
    ~list_base() {while (tail) { pop_back_only();}}

    size_t  size() { return sz;}

    void reverse(){
        list_node_base *p = head;
        while (p){
            std::swap(p->prev, p->next);
            p = p->prev;
        }
        std::swap(head, tail);
    }

    void push_back(list_node_base *pos){
        push_back_only(pos);
        ++sz;
    }

    void pop_back(){
        pop_back_only();
        --sz;
    }

    void erase(list_node_base *pos){
        if(pos == head){
            head = head->next;
            if(head) {head->prev = 0;}
            else { tail = 0; }
        }else if(pos == tail){
            tail = tail->prev;
            tail->next = 0;
        }else{
            pos->prev->next = pos->next;
            pos->next->prev = pos->next;
        }

        delete pos;
        --sz;
    }
};

template <typename T>
class list: public  list_base{
private:
    typedef list_node<T> node_type;
    typedef list_base base_type;

    void push_back_only(T const & v){
        base_type::push_back_only(new node_type(v, 0, 0));
    }

public:
    typedef T value_type;
    typedef T& reference;
    typedef const T& const_reference;
    typedef list_iterator<T> iterator;
    
    list() : list_base(){}
    ~list(){}
    
    iterator begin(){ return iterator(reinterpret_cast<node_type*>(head));}
    iterator end()  { return iterator();}
    
    list& push_back(T const & v){
        node_type*n = new node_type(v, 0, 0);
        base_type::push_back(n);
        return *this;
    }
    
    list& pop_back(){
        base_type::pop_back();
        return *this;
    }
    
    void assign(list &r){
        iterator i = begin();
        iterator r_i = r.end();
        
        if(sz < r.sz){
            for(; i != end(); i++, r_i++){*i = *r_i;}
            while (r_i != r.end()) push_back_only(*r_i);
            sz = r.sz;
        }else{
            for(; r_i != r.end(); i++, r_i++){*i = *r_i;}
            while (sz != r.sz) base_type::erase(tail);
        }
    }
    
    void erase(iterator i){
        base_type::erase(i.pos);
    }
};

 

Visual C/C++ 编程精选集锦源代码是一个涵盖了多个不同领域的精选代码集。其中包括了图形界面设计、算法实现、数据结构、网络编程等等方面的代码。这些源代码通过精心筛选,可以帮助程序员们更好地理解和学习这些领域的编程技术。 在图形界面设计方面,这个集锦中包括了一些常用的界面设计方法和技巧,比如窗口创建、控件布局、事件处理等方面的代码实现。这些代码可以帮助程序员更好地理解如何使用 Visual C/C++ 来设计各种不同类型的界面。 在算法实现和数据结构方面,这个集锦中也包括了一些常用的算法和数据结构的实现代码,比如排序算法、查找算法、链表、树等数据结构的实现。这些代码可以帮助程序员更好地理解和掌握常用的算法和数据结构的实现方法。 在网络编程方面,这个集锦中也包括了一些常用的网络编程代码,比如 socket 编程、多线程编程、网络通信协议等方面的代码实现。这些代码可以帮助程序员更好地理解和掌握网络编程的相关知识和技术。 总的来说,这个 Visual C/C++ 编程精选集锦源代码是一个非常有价值的学习资源,可以帮助程序员们更好地学习和掌握各种不同领域的编程技术。希望程序员们能够通过学习这些源代码,不断提升自己的编程技能,为自己的职业发展打下坚实的基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值