美文网首页
chapter13 异常处理: vector 的 实现

chapter13 异常处理: vector 的 实现

作者: my_passion | 来源:发表于2022-06-22 08:43 被阅读0次

13.1 概述

            检查错误: callee
         /      |       无法处理 throw
        /       |       希望处理 catch
1 分离            | 传递
        \       |
         \      |/
            处理错误: caller
            
2 抛出异常
    
    栈展开
        异常 从 `抛出点` 开始, `向上` 传递到 处理程序
    
    空 异常说明 throw() 作用等价于 noexcept, 即 若抛出异常, 则 程序终止
        void f(int) throw();

13.2 vector 的实现

    异常安全代码的 范例

1 简单 vector

    (1) data
    
        1 个 分配器 alloc
        
        3个指针: elem / space / last 分别指向 
            
            分配空间   start
            
            可扩展空间 start == 元素序列 end
            
            分配空间   end 

    (2) ctor
        
        template<class T, class A = allocator<T> >
        ...
        vector(size_type n, const T& val = T(), const A& a = A() );
        
        [1] 分配内存 elem = alloc.allocate(n)
        
        [2] 另 2 个指针 赋值
        
        [3] 逐元素 `构造 新值的 copy`
                
            for(T* p) 
                alloc.construct(p, val);
        
        2处可能引发 异常
            
            [1] allocate() 抛出异常
            
            [2] T `copy ctor 无法 copy 新值`
                construct(p, val) ...
    
    (3) 带 异常处理 的 ctor
            
            try{}
            catch(...)
            {
                逐元素销毁 // for (Iter q = beg, ...) 
                           //    (&*q)->~T();
                重新抛出   // throw;
            }
        }

经验: try 书写 异常安全代码难度 远远超出人们的预期

(1) vector 实现 没用 try 块 ( 除了 隐藏在 原始_copy() 中那个 之外 )

    |
    |   替换为 更简单有效的方法 
    |/

(2) RAII + 小心 设计操作顺序 以 确保, 抛出异常 时,

vector 不被改变 ( push_back() ) 或 至少处于 (我们认为的) 有效状态 ( copy assignent )

2. 引入 辅助 struct (vector_base) 以 directly 处理 T 类型的 memory

    好处: 简化代码 + 降低 忘记释放内存的 可能性
        
    (1) ctor 
    
            alloc.allocate(size) + 3Ptrs 指向相应位置 

        dtor 
            alloc.deallocate(elem, last - elem)
        
    (2) copy delete
        
        那 vector copy 如何实现 ? 
            vector copy ctor/assignement
            
    (3) move
        
        [1] move ctor
            
            lhs 
                ptrs/alloc 初始化(copy) 为 rhs's ptrs/alloc 
                
            rhs 
                ptrs 置 nullptr 
            
        [2] move assignment 
            
            lhs 已存在 => swap(*this, rhs);        

直接 move vector_base, 即 move 任意已分配 memory 的 ownership : 优化效率/性能

3 vector 实现

    template <class T, class A = alloctor<T> >
    class vector
    {
    private:
        // 只有1个 成员数据 
        vector_base<T, A> vb;
        
        // dtor 的 辅助(销毁元素的)函数
        destory_elements(); 
    
    public:
        // (1) 6 大函数 
            
        explicit vector(size_type n, const T& val = T(), const A& a = A() );
        
        ~vector() { destory_elements(); }
            
        // (2) 尺寸/容量函数 
        
        size_type size() const { return vb.space - vb.elem; }
        size_type capacity() const { return vb.last - vb.elem; };
            
        // (3) 改变尺寸 的 4 大函数
        
        // 10. 第 10 大函数
        void clear() { resize(0); }
        
    };

(1) dtor 辅助函数
    
    逐成员销毁: 显式调 T 的 dtor
    
    note
        没有哪种方法 能 切实有效地 防止 dtor 抛出异常
    
(2) ctor

    调 成员 vb 的 ctor: vb{a, n}

    原始_fill();
        
(3) copy ctor

    调 成员 vb 的 ctor: vb{v.alloc, v.size() }
        
    uninitialized_copy() from rhsVecMemory 

(4) 移动 ctor
    
    对 `成员 vb` 用 `std::move` 转移 所有权 

(5) 移动 赋值
    
    销毁 所有元素
    对 `vector` 用 `swap` 转移 所有权 

(6) copy assignement

    version1    `强保障`   缺点: 难维护
        midVecBase 
            uninitialized_copy from rhsVecMemory        : uninitialized_copy(rhs.begin(), rhs.end(), midVecBase.elem)
            move memory's ownership 到 dstVec's vecBase : swap(vb, midVecBase)
        scope 结束时, midVecBase 的 dtor 隐式 `释放 (被转移给的) 旧空间`
        |
        |
        |/
    version2    `强保障`   易维护, 与 version1 性能接近
        midVec         : 从 rhs copy ctor 
        move ownership : std::swap(*this, midVec)
        |               
        |                   效率高于        
        |   元素 (copy) 赋值 —— —— ——> 析构 (1 个元素) + 构造 (1个元素 )
        |/  
    version3    `基本保障`  复杂度高
        if dstVecCapacity < rhsVecSize 
            version2
        else // >=
            if dstVecSize >= rhsVecSize 
                copy() rhsVecSize
                多余 elem: 逐个销毁  
                    p->~T();
                    
            else // < 
                copy() dstVecSize
                额外 elem:
                    uninitialized_copy() from rhsVec
                                
        基本保障: 抛出异常时, `正被 copy 的 elem 可能 既非旧值 也非新值` -> 视 vector 为 有效状态 
             
    ————————————————————————————————————————————————————————————————————————————————
    copy 赋值 vs. 移动 赋值 
    ————————————————————————————————————————————————————————————————————————————————                            
    copy 赋值 |  const 引用形参   |  copy 后 右对象(左值 / 右值) 可能 不会被 立即销毁 
        
    移动 赋值 |  右值  引用形参   |  移动 后 右对象(右值)               会被 立即销毁 
    ————————————————————————————————————————————————————————————————————————————————            

(7) reserve()

    if newCapacity 更小
        doNothing, return
    else 
        对 vector 扩展 capacity = 分配 newSpace + 元素 移入
    
    template<class T, class A>
    void vector<T, A>::reserve(size_type newCapacity);

    1) version1 
    
        [1] 建 newVector   
        [2] copy() 旧 elem 到 newSpace                                                                                                    
        [3] move ownership                                                                                                                      
        [4] scope 结束: newVector dtor 隐式 `销毁 旧值 + 释放 旧空间`                    
                                                                                                                                                                                
    2) version2 : `基本保障: 要 避免 move 操作 抛出异常`                                                                          
                                                                                                    
        [1] 建 newVecBase 
        
        [2] 自定义 uninitialized_move() 算法, 在 各 newElemPos 用 oldElemValue `移动 构造` newElem
        
        [3] move memory's ownership: swap(newVecBase, vb)

        [4] scope 结束: newVecBase 的 dtor 隐式 仅 `释放 旧空间`
        
        template<typename In, typename Out>                                 
        Out uninitialized_move(In b, In e, Out oo)                           
        {                                                                   
            for(; b != e; ++b, ++oo)                                        
            {                                                               
                new (static_cast<void*>(&*oo) ) T { std::move(*b) };  
                                                                            
                b->~T();  // `销毁/析构 旧空间中 元素`
            }
        }
    
        reserve 一旦移动构造了元素, vector 迭代器 可能 失效 

(8) resize()

    template<class T, class A>
    void vector<T, A>::resize(size_type newSize, const T& x);
        
    [1] 先调 reverse(newsize)
    
    [2]
        if newSize 更大
            uninitialized_fill(): 构造 额外 elem 
        else 
            destory():            销毁 多余 elem  
    
    [3] 更新 space&last 指针: 均指向 memory newsize 尾
    
    
        template<typename In>
        void destory(In b, In e)
        {
            for(; b != e; ++b)
                b->~T();
        }

(9) push_back()

    从 异常安全 角度看, push_back() `与 copy assignment 相似`
    
        若 copy 构造 抛出异常, 仍保证了 vector 内容没变 
                        
        原因: 
            copy 构造 后的 更新 spacePtrPos 没被执行
            vector 因 reserve() 可能 扩容而 换了 space, 但 data/content 却不变 
                
    template<class T, class A>
    void vector<T, A>::push_back(const T& x);
    
    [1]
        if(capacity() == size() )   // 若 满载 
            reserve(sz ? 2*sz : 8); //  扩capacity 1 倍 或 分配为 8 (若为 初始分配)
    
    [2] 在 pushedPos 用指定值 `copy 构造` 新值  
        
        vb.alloc.construct(&vb.elem[size()], x) 
    
    [3] 更新 spacePtrPos
    
        ++vb.space;
325.jpg 326.jpg 327.jpg 328.jpg 329.jpg 330.jpg 331.jpg 332.jpg 333.jpg 334.jpg

相关文章

  • chapter13 异常处理: vector 的 实现

    13.1 概述 13.2 vector 的实现 1 简单 vector 经验: try 书写 异常安全代码 的 难...

  • 11|第十一课:异常处理

    一、异常处理 springMVC实现异常处理,必须实现HandlerExceptionResolver接口。 该接...

  • Spring 之异常处理

    spring的异常处理 spring的异常处理,有两种方式 1、实现HandlerExceptionResolve...

  • 异常处理器

    springmvc在处理请求过程中出现异常信息交由异常处理器进行处理,自定义异常处理器可以实现一个系统的异常处理逻...

  • SpringMVC异常处理器

    SpringMVC在处理请求过程中出现异常信息交由异常处理器进行处理,自定义异常处理器可以实现一个系统的异常处理逻...

  • vector

    vector构造函数 vector v;//采用模板实现类实现,默认构造函数 vector(v.begin(), ...

  • Java中 Vector的使用详解

    Vector 可实现自动增长的对象数组。java.util.vector提供了向量类(Vector)以实现类似动态...

  • SpringBoot接口 - 如何优雅的写Controller并

    内容目录 为什么要优雅的处理异常 实现案例@ControllerAdvice异常统一处理Controller接口运...

  • C/C++基础知识(六)——异常、容器、命名空间

    异常处理 容器 序列式容器 元素排列顺序和元素本身无关,有添加顺序决定序列式容器有:vector,list,deq...

  • Java虚拟机-异常的处理

    1 异常处理 异常处理的两大组成要素是抛出异常和捕获异常。这两大要素共同实现程序控制流的非正常转移。 2 抛出异常...

网友评论

      本文标题:chapter13 异常处理: vector 的 实现

      本文链接:https://www.haomeiwen.com/subject/mgsyvrtx.html