zoukankan      html  css  js  c++  java
  • Effective STL 学习关于容器

    一、容器的选择

      标准STL序列容器:vector,string,deque,list。其中前三种是连续内存容器,list是节点内存容器(非连续内存)

      序列容器特点:任意位置删除、插入元素;插入、删除时元素会移动;元素是有顺序的,可以随机访问(list除外),vector数据内存兼容C,string支持引用计数,list支持多元素插入事务性语义(连续内存容器也支持但是性能差);基于节点的非删除迭代器指向元素,迭代器不会失效。

      标准STL关联容器:set,mutiset,map,mutimap。

    二、编写容器无关代码

      1. 使用typedef 如:std::vector<int> 可以写成 typedef std::vector<int> IntContainer;

      2. 当容器需要依赖特定方法时,可以对容器就行封装,提供统一的方法(性能稍微有点损耗);

        如:

    class Container
    {
        public:
            size_t Size();
            bool HasNext();
            int Next();
            ........
        private:    
            vector<int> m_vec;
    }            
    

    三、使容器里对象的拷贝轻量且正确

      std::vector<Object> vec;

      vec.push_back(obj);  //会调用Object的拷贝构造函数对元素就行拷贝插入容器中

      1.如果上面Object对象比较大,插入元素的代价是比较大的,此时容器应该存对象指针即定义为:std::vector<Object *> vec;担心元素内存释放可用smart_ptr智能指针。

      2.当Object是基类时拷贝可能导致累被分割。

    四、用empty代替size()检查容器是否为空

      1.splice函数和size函数谁是常数时间函数和线性函数时间的取舍问题。size可能是线性时间实现,但empty能肯定是常数时间函数。

    五、尽量用区间成员函数代替单元素函数

      1.使用区间成员函数:assign,insert ,erase。。。,可以避免手写循环,简化程序并且使程序更直观

        如:insert(开始插入位置iterator,插入区间起点,插入区间终点);

    六、读取固定格式文件的一种方便实现

     ints.dat存放的是一组int值时可以这样读文件

    ifstream dataFile("ints.dat");
    istream_iterator<int> dataBegin(dataFile);
    istream_iterator<int> dataEnd;
    list<int> data(dataBegin, dataEnd);

    //上面代码不能这样实现
    list<int> data(istream_iterator<int>(dataFile), istream_iterator<int>());//并不是所以编译器都会认

    七、一个错误:

      class Widget {...}; // 假设Widget有默认构造函数
      Widget w(); //编译器会认为是定义了一个不带参数的w函数,返回值为Widget,而不是认为是定义了一个Widget变量w。  

    八、用for_each和智能指针,管理指针容器中new的元素

      1.for_each

    std::vector<Object *> vec;
    
    struct DeleteObject
    {
        template<typename T>
        void operator()(const T* ptr) const 
        { 
            delete ptr;
            ptr = NULL;
        } 
    };
    ...//插入元素操作
    for_each(vec.begin(), vec.end(), DeleteObject()); //删除元素
    

      2.智能指针

    typedef shared_ptr<Object> ShareObj;
    
    vector<ShareObj> vec;
    
    vec.push_back(ShareObj(new Object));

    //注意不要用auto_ptr,auto_ptr会转移对象拥有权
    //原因:
    对象转移:
    auto_ptr<Object> obj1(new Object); //obj1指向一个Object
    auto_ptr<Object> obj2(obj1);    //obj1指向的对象转移给obj2,obj1指向NULL
    obj1 = obj2;             //obj1指向Object,obj2指向NULL
    进而做以下操作可能发生错误:
    auto_ptr<Object> obj = vec[i]; //如果做此操作会使vector中第i个元素对象指向NULL,很容易出现你不想要的结果。

    九、不同容器删除元素的方法:

      1. vector,string,deque

    Container<int> c;  //容器为vector,string,deque
    c.erase(remove(c.begin(), c.end(), 1963), c.end());   //erase remove 惯用法  
    

      2.list

    list<int> c;  
    c.remove(1123);     
    

      3.set, mutiset, map, mutimap等关联容器

    set<int> c;
    c.erase(1212);
    

      4.删除容器中有特定值的元素

    bool badValue(int val);
    
    Container<int> c
    c.erase(remove_if(c.begin(), c.end(), badValue), c.end()); //vector,string,deque
    
    c.remove_if(badValue);                          //list
    
    
    //关联容器
    for (Container<int>::iterator i = c.begin(); i != c.end(); /*nothing*/ )
    {
        if (badValue(*i)) 
           c.erase(i++);         // 对于坏的值,把当前的
        else ++i;                   // i传给erase,然后
    }                                   // 作为副作用增加i;
    
    //非关联容器还可以用remove_copy_if函数,先把不删除的的元素拷贝到新的容器,然后把新容器通过swap函数交换到旧容器中
    //非关联容器用循环的方法 for (Container<int>::iterator i = c.begin(); i != c.end(); ) { if (badValue(*i)) { i = c.erase(i); // 通过把erase的返回值 } // 赋给i来保持i有效 else { ++i; } }

      

      

      

    发布选项

  • 相关阅读:
    教育网玩QQ游戏解决办法
    国家重点实验室分布<转>
    MySQL存储过程错误No data zero rows fetched, selected, or processed
    安装Oracle Developer后 pl sql无法使用
    Jsp开发入门
    开源项目MiniOA协同办公系统介绍
    JavaScript实现网页单击事件
    (转)普及基础知识一
    “人脸识别程序”总结
    (转)如何加速Altera的EDA工具? (IC Design) (Quartus II) (Nios II) (SOPC Builder)
  • 原文地址:https://www.cnblogs.com/4tian/p/2874103.html
Copyright © 2011-2022 走看看