这是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函数的定义。这样就是为了避免编译器 的安全性。