zoukankan      html  css  js  c++  java
  • C++primer_拷贝控制之13.26联系控制成员实现类值行为

    这是StrBlob.h头文件,所有函数均定义为内联函数

    #ifndef     _MY_STRBLOB_H
    #define     _MY_STRBLOB_H
    #include<vector>
    #include<string>
    #include<initializer_list>
    #include<memory>
    #include<stdexcept>
    using namespace std;
    
    class StrBlobPtr;
    class StrBlob
    {
        friend class StrBlobPtr;
        public:
            typedef vector<string>::size_type size_type;
            StrBlob();
            StrBlob(initializer_list<string>il);
            StrBlob(vector<string>*p);
            StrBlob(StrBlob&s);
            StrBlob&operator=(StrBlob&rhs);
            size_type size() const { return data->size(); }
            void push_back(const string &t) { data->push_back(t); }
            void pop_back();
            string &front();
            const string &front()const;
            string &back();
            const string &back()const;
            StrBlobPtr begin();
            StrBlobPtr end();
            StrBlobPtr begin()const;
            StrBlobPtr end()const;
        private:
            shared_ptr<std::vector<std::string>>data;
            void check(size_type i, const string &msg)const;
    };
    class StrBlobPtr//这个类是智能指针管理类
    {
        friend class StrBlob;
        friend bool eq(const StrBlobPtr&, const StrBlobPtr&);
    public:
        StrBlobPtr() :curr(0) {};
        StrBlobPtr(StrBlob &a, size_t sz = 0) :wptr(a.data), curr(sz) {}
        StrBlobPtr(const StrBlob &a, size_t sz = 0) :wptr(a.data), curr(sz) {}
        string &deref()const;
        string &deref(int off)const;
        StrBlobPtr&incr();//前缀递增
        StrBlobPtr&decr();//前缀递减
    
    
    private:
        shared_ptr<vector<string>>check(size_t, const string &)const;//若检查成功,check返回一个指向vector的shared_ptr指针
        weak_ptr<vector<string>>wptr;//在这里保存一个weak_ptr,那么底层元素可能被销毁
        size_t curr;//在数组当前位置
    
    };
    
    inline StrBlob::StrBlob() :data(make_shared<vector<string>>()) {}
    inline StrBlob::StrBlob(initializer_list<string> il) : data(make_shared<vector<string>>(il)) {}
    inline StrBlob::StrBlob(vector<string>*p) : data(p) {}
    inline StrBlob::StrBlob(StrBlob&s) : data(make_shared<vector<string>>(*s.data)) {}
    inline StrBlob&StrBlob::operator=(StrBlob&rhs)
    {
        data = make_shared<vector<string>>(*rhs.data);
        return *this;
    }
    
    inline void StrBlob::check(size_type i, const std::string &msg)const
    {
        if (i >= data->size())
            throw out_of_range(msg);
    }
    inline string&StrBlob::front()
    {
        check(0, "front on empty StrBlog");
        return data->front();
    }
    inline string&StrBlob::back()
    {
        check(0, "back on empty StrBlog");
        return data->back();
    }
    inline const string&StrBlob::front() const
    {
        check(0, "front on empty StrBlog");
        return data->front();
    }
    inline const string&StrBlob::back() const
    {
        check(0, "back on empty StrBlog");
        return data->back();
    }
    inline void StrBlob::pop_back()
    {
        check(0, "pop_back on empty StrBlog");
        return data->pop_back();
    
    }
    
    //第StrBlobPtr类函数定义开始
    inline shared_ptr<vector<string>>StrBlobPtr::check(size_t i, const string &msg)const
    {
        auto ret = wptr.lock();
        if (!ret)
            throw runtime_error("unbound StrBlobPtr");
        if (i >= ret->size())
            throw out_of_range(msg);
        return ret;//检查容器是否存在,存在的话返回vector的shared_ptr计数
    }
    inline string &StrBlobPtr::deref(int off)const
    {
        auto p = check(curr, "dereference past end");
        return (*p)[curr + off];
    }
    inline string &StrBlobPtr::deref()const
    {
        auto p = check(curr, "dereference past end");
        return (*p)[curr];
    }
    inline StrBlobPtr&StrBlobPtr::incr()//前缀递增
    {
        check(curr, "increment past end of StrBlobPtr");//先做检查,若现在已经指向响亮的尾后位置,那么就不能递增他
        ++curr;
        return *this;
    }
    inline StrBlobPtr&StrBlobPtr::decr()//前缀递减
    {
        --curr;
        check(-1, "Decrement past begin of StrBlobPtr");//先做检查,若之前已经指向0,那么现在的地址就是非法地址,那么就抛出异常;
    
        return *this;
    }
    
    //StrBlob的begin和end操作
    inline StrBlobPtr StrBlob::begin()
    {
        return StrBlobPtr(*this);
    }
    inline StrBlobPtr StrBlob::end()
    {
        auto ret = StrBlobPtr(*this, data->size());
        return ret;
    }
    //StrBlob的begin和end操作const版本
    inline StrBlobPtr StrBlob::begin()const
    {
        return StrBlobPtr(*this);
    }
    inline StrBlobPtr StrBlob::end()const
    {
        auto ret = StrBlobPtr(*this, data->size());
        return ret;
    }
    inline bool eq(const StrBlobPtr&lns, const StrBlobPtr &rhs)
    {
        auto l = lns.wptr.lock(), r = rhs.wptr.lock();//函数的目的是为了确认两个容器底层是否为同一个容器
        if (l == r)
            return(!r || lns.curr == rhs.curr);//若是两个指针为空,或者元素位置相同那么他们就相同;
        else
            return false;
    }
    inline bool neq(const StrBlobPtr&lns, const StrBlobPtr &rhs)
    {
        return !eq(lns, rhs);
    }
    #endif
    
    

    头文件main.cpp如下

    #include "StrBlob.h"
    #include <iostream>
    using namespace std;
    int main(int argc, char **argv)
    {
    
    
        StrBlob b1;
        StrBlob b2 = { "a", "an", "the" };
        b1 = b2;
        b2.push_back("about");
        cout << "b2大小为" << b2.size() << endl;
        cout << "b2首尾元素为" << b2.front() <<" "<< b2.back()<<endl;
        cout << "b1大小为" << b1.size() << endl;
        cout << "b1首尾元素为" << b1.front() << " " << b1.back() << endl;
        //结果证明了此时的b1和b2已经不再是统一底层元素了
    
        StrBlob b3 = b1;
        b3.push_back("next");
        cout << "b3大小为" << b3.size() << endl;
        cout << "b3首尾元素为" << b3.front() << " " << b3.back() << endl;
    
        cout << "b1全部元素:" << endl;
        for (auto it =b1.begin();neq(it,b1.end());it.incr())
        {
            cout << it.deref() << endl;
        }
        system("pause");
        return 0;
    }

    此时运行结果如下:
    这里写图片描述

    但是请记住,当把所有函数定义为内联函数时,请不要将执行类与实现分离的傻瓜式分离,因为内联函数本身就是在头文件内部定义的,与此同时,若是将实现放在类对应的cpp文件中,那么就会导致失败,而且函数对于编译器是不可见的
    效果如下:
    这里写图片描述
    所以在一般情况下,内联函数必须放在头文件中,这样对编译器来说是安全可见 的。在多文件程序中,由于inline函数可能会被编译器插入到每个文件里面,所以如果把inline函数放在某个cpp文件中,编译器可能不能找到这个inline函数而出错,但如果放在头文件中,由于编译器总是先处理所有的头文件,所以能先找到inline函数的定义。这样就是为了避免编译器 的安全性。

  • 相关阅读:
    图片滚动懒加载用jquery-lazyload 与手动Jquery 写
    穿梭框(filter过滤方法,sort排序 v-model)
    选择添加好友(包含 去重,删除splice 等) v-show(解决显示隐藏闪动问题)
    求数组中最小的数值(结合apply() call())
    Vue
    js递归
    使用kdf 元素来接收键盘的输入指令
    编辑滚动条样式
    【IntelliJ IDEA】Debug调试的使用记录
    福利:IntelliJ IDEA 破解激活教程
  • 原文地址:https://www.cnblogs.com/VCctor/p/5100678.html
Copyright © 2011-2022 走看看