编写自己的String类————使类对象获得数值功能第十二章心得

1 实现Str类(不可管理内存)

本次实现是在之前编写Vec类的基础上进行。当然也可以在vector类的基础上进行。

1.1 构造函数

Str的默认构造函数隐式调用Vec类的默认构造函数,生成一个空的Str类型对象。由于Str类还有其他的构造函数,因此显示定义默认构造函数是必要的。

值得注意的是最后一个构造函数是一个模版函数。由于是模版函数,因此它实际上是定义了一组构造函数,随着不同类型的迭代器实例化出不同的构造函数。

例如,这个构造函数可以用于被从一个字符数组构造一个Str类型对象,也可以从Vec<char>类型对象构造Str类型对象。

class Str{
public:
	typedef Vec<char>::size_type
	//构造函数
	//默认构造函数,创建一个空的Str
	Str(){}
	//生成一个Str对象,包含c的n个副本
	Str(size_type n, char c):data(n,c){}
	//生成一个Str对象并使用一个空字符结尾的字符数组来初始化
	Str(const char* cp){
		std::copy(cp, cp+std::strlen(cp), std::back_inserter(data));
	}
	//生成一个Str对象并使用迭代器b和e之间的内容对它进行初始化
	template<class In>Str(In b, In e){
		std::copy(b, e, std::back_inserter(data));
	}
private:
	Vec<char> data;
}

构造函数中还实现了类型转换,通过Str(const char* )构造函数将const char*类型的字符串数组转换为Str类型对象。

例如:

Str s;
s = "hello"

这个表达式中,编译器实际上调用Str(const char* )构造函数为这个字符串字面量构造一个没有名称、局部的、临时的Str类型对象,然后在调用编译器自动生成的赋值运算符函数将这个一临时值赋给s。

1.2 复制构造函数、赋值运算符函数、析构函数

Str类本身没有分配内存的能力,它将管理内存的细节留给了编译器,编译器将自动生成相应的函数,而这些函数通过调用Vec中的相应函数进行操作。

通常一个不需要析构函数的类,也不需要定义复制构造函数或赋值操作符函数。

1.3 重载运算符函数

1.3.1 索引运算符函数

索引运算符函数必须是成员函数。定义了两个版本的索引运算符,一个可以对返回的字符进行写操作,另一个不能对之进行修改。

class Str{
public:
	char& operator[](size_t i){return data[i];}
	const char& operator[](size_t i) const{return data[i];}
private:
	Vec<char> data;	
}

1.3.1 输出运算符函数

判断一个函数是否应该是成员函数时,一般判断的方法是看这个函数是否会改变对象的状态。

输入运算符函数当然会改变对象的状态,因为它在使用输入操作时会将一个新值重新读入已存在的对象。

对于二元运算符函数,其左操作数必须作为函数的第一个参数,右操作数必须作为函数的第二个参数。如果该运算算符函数是成员函数,那么第一个参数(也就是左操作数)总是会默认传递给该成员函数。

如果将输入运算符作为成员函数,会引发下面的效果:
我们希望的是:

cin >> s;
//等价于
cin.operator >> (s);

它调用了对象cin的被重载的>>运算符。这种行为暗示着>>运算符必须是istream的一个成员。

由于我们没有权限修改istream的定义,也就不能将这个操作添加到它里面。

如果我们将operator>>作为Str的一个成员,那么用户将不得不用如下的方式来对Str进行输入操作:
实际效果:

s.operator >> (cin);
//等价于
s >> cin;

这与整个库的语法规则不同,因此输入函数不能作为类的成员函数。输出函数也是一样的。

继续完善Str类:

//类外添加声明
std::ostream& operator>>(std::ostream&, Str&);

定义

ostream& operator<<(ostream& os, const Str& s){
	for(Str::size_type i = 0;i != s.size();++i)
		os << s[i];
	return os;
}

1.3.2 输入运算符函数

它需要从输入流中读出 字符并将其存储起来。每次使用输入运算符的时候,会忽略开头的空格佛祖,然后连续读出其他字符并存储起来,直到遇到另一个空格字符或遇到一个文件结尾标志为止。

istream& operator>>(istream& is, Str s){
	//抹去存在的值
	s.data.clear();//私有成员
	//按序读入字符并忽略前面的空格字符
	char c;
	//只判断循环,为的是清楚前面的空白
	while(is.get(c) && isspace(c));
	//如果读到非空格字符,重复以上操作直到遇到一个空格字符为止
	if(is){
		do s.data.push_back(c);//私有成员
		while(is.get(c) && !isspace(c));
		//如果遇到一个空格字符,将它放在输入流的后面
		if(is)
			is.unget;//取消最近一次从输入流中读取一个字符的操作
	}
}

继续完善Str类:

//类外添加声明
std::istream& operator>>(std::istream&, Str&);

如果这样话,私有成员那两条语句或报错,因为operator>>不是成员函数,不能访问s的私有成员data。如果为data写一个存取器函数,这不能满足要求。因为我们要将像data写入新的数值,不满足只读的要求。

因此我们需要用到友元函数。友元函数拥有与成员函数相同的访问权利。

友元函数的声明可以加在类定义的任何地方:将它加在private标识后面与加在public标示后面没有任何区别。由于友元函数具有特殊的访问权利,因此它是类接口的一部分。一般会将全部友元函数的声明放在一起作为一个相对独立的组。

class Str{
friend std::istream& operator>>(std::istream&, Str&);
}

1.3.3 复合加法赋值运算符函数

由于+=运算符函数会改变运算符的左操作数,因此将它写成成员函数。

class Str{
public:
	Str& operator += (const Str& s){
		std::copy(s.data.begin(),s.data.end(),std::back_inserter(data));
		return *this;/间接引用,返回对象
	}
}

1.3.4 加法运算符函数

由于加法运算符函数没有改变左右两个操作数,因此把它写成非成员函数。

首先定义一个局部变量r,然后将其初始化为s的一个副本来生成一个新的Str类型对象,这个初始话过程中用到了Str的复制构造函数,然后调用+=运算副函数,将r与t连接作为r的新值。最后返回r(再次因此调用复制构造函数)作为结果。

Str operator+ (const Str& s, const Str& t){
	Str r = s;
	r += t;
	return r;
}

对于

Str name = "jiangxueHan"
Str greeting = "Hello,"+name+"!";

等同于下面

Str temp1(""Hello");//Str::Str(const char*)
Str temp 2 = temp1 + name;;//operator(const Str&,const Str&);
Str temp3("!");//Str::Str(const char*)
Str S = temp2 + temp3;//operator+(const Str&, const Str&)

由于operator+函数的参数两个都是Str类型,因此遇到混合类型表达式的时候,每次都要调用构造函数将const char*类型转换为Str类型,这样会导致代码用到大量的临时变量,因此这种方法是非常消耗内存的。实际上,真正标准库的string类不是依赖于类型转换实现混合类型的操作数相加,而是重置改加号运算符,为每一种可能的操作数类型的连接定义一个版本。

1.4 汇总代码

// 使用memory管理内存
// Created by MacBook Pro on 2020-03-17.
//

#ifndef ACM_STR_H
#define ACM_STR_H

#include "Vec.h"
#include <iostream>
class Str{
    friend std::istream& operator>>(std::istream&, Str&);

public:
    //实现+=运算符
    Str& operator += (const Str& s){
        std::copy (s.data.begin(), s.data.end(), std::back_inserter(data));
        return *this;
    }

    typedef Vec<char>::size_type size_type;
    //默认构造
    Str(){}
    //生成一个Str对象,包含c的n个副本
    Str(size_type n, char c):data(n,c){}//使用Vec类中的构造函数构造data数据
    //生成一个Str对象并使用一个空字符结尾的字符数组来初始化
    Str(const char* cp){
        std::copy(cp, cp + std::strlen(cp), std::back_inserter(data));
    }
    //生成一个Str对象并使用迭代器b和e之间的内容对他进行初始化
    template<class In>Str (In b, In e){
        std::copy(b, e, std::back_inserter(data));
    }

    //大小
    size_type size() const { return  data.size();}

    //索引
    char& operator[](size_type i) { return  data[i];}
    const char &operator[](size_type i) const { return  data[i];}


private:
    Vec<char> data;
};
//输入运算符
std::istream& operator>>(std::istream&, Str&);
//输出运算符
std::ostream& operator<<(std::ostream&, const Str&);
//加号运算符
Str operator+(const Str&, const Str&);

//输出运算符定义
std::ostream& operator<<(std::ostream& os, const Str& s){
    for (Str::size_type i = 0; i != s.size(); ++i) {
        os << s[i];
    }
    return  os;
}
//输入运算符的定义
std::istream& operator>>(std::istream& is, Str& s){
    //抹去存在的值(s)
    s.data.clear();
    //按序读字符并忽略前面的空格字符
    char c;
    //值进行循环条件,不进行其他工作
    while(is.get(c) && isspace(c));
    //读入非空白字符
    if(is){
        do{
            s.data.push_back(c);//直到遇到一个空格字符或超出输入范围
        }while(is.get(c) && !isspace(c));
        //如果遇到一空格字符,将它放在输入流的后面
        if(is){
            is.unget();
        }
    }
    return is;
}

//加号运算符的定义
Str operator+ (const Str& s, const Str& t){
    Str r = s;
    r += t;
    return r;
}


#endif //ACM_STR_H

2 Str_c(自行管理内存)

2.1 构造函数

public:
    typedef size_t size_type;
    typedef char* iterator;
    typedef const char* const_iterator;

    //构造
    //默认构造
    Str_c(){create(0,'\0');}
    //复制构造
    Str_c(const Str_c& s){create(s.begin(), s.end());}
    //带参构造(长度、字符)
    Str_c(size_type n, char c){create(n,c);}
    //带参构造(迭代器始末)
    template<class In> Str_c( In b, In e){create(b,e);}
    //带参构造(类型转换)
    Str_c(const char* cp){create(cp, cp + std::strlen(cp));}
    private:
    char* d;//指向字符串的第一个字符的指针
    char* avail;//指向最后一个有值的字符后面两位的指针
    char* limit;//指向字符串的最后一个字符后面的指针
    std::allocator<char> alloc;

    //构造函数调用
    void create(size_type, char);
    template <class In> void create(In,In);

定义:

void Str_c::create(Str_c::size_type n, char c) {
    d = alloc.allocate(n + 1);
    limit = avail = d + n + 1;
    std::uninitialized_fill(d, d + n, c);
//    alloc.construct(data + n, '\0');

}

template <class In>
void Str_c::create(In b, In e) {
    d = alloc.allocate(e - b + 1);//多分配一个长度存储空白字符
    limit = avail = std::uninitialized_copy(b, e, d) + 1;//指向e的后面两个为止(后面还多一个空白字符)
}

2.2 赋值运算符函数

public:
    //赋值运算符
    Str_c&  operator=(const Str_c&);
    Str_c&  operator=(const char*);

定义:

Str_c& Str_c::operator=(const Str_c &s) {
    if(&s != this){
        uncreate();
        create(s.begin(),s.end());
    }
    return *this;
}

Str_c&  Str_c::operator=(const char *s) {
    uncreate();
    create(s, s + strlen(s));
    return *this;
}

2.3 析构函数

public:
   //析构函数
    ~Str_c(){uncreate();}
private:
    //析构函数
    void uncreate();    
void Str_c::uncreate() {
    if(avail != 0){
        iterator it = avail;
        while(it != d){
            alloc.destroy(--it);
        }
        alloc.deallocate(d, limit - d);
    }
    d = avail = limit = 0;
}

2.4 运算符函数

2.4.1 索引运算符

publicchar& operator[](size_type i){ return d[i];}
    const char&operator[](size_type i) const{ return  d[i];}

2.4.2 复合加法赋值运算符

public:
    //复合加法赋值运算符
    Str_c& operator+=(const char* cp){
        append(cp, std::strlen(cp));
        return *this;
    }

    Str_c&operator+=(const Str_c& s){
        append(s);
        return *this;
    }
private:
    //复合加法赋值运算符
    void append(const char*, const size_type);
    void append(const char);
    void append(const Str_c&);
    void prepend(const char*, const size_type);
void Str_c::append(const char* str, const Str_c::size_type n) {
    size_type new_length = n + size() + 1;//加入字符串后的长度

    if(limit == avail || avail + n  >= limit){
        ptrdiff_t room = 2 * (limit - d);
        while(size_type(room) < new_length){//直到分配的空间可以容纳加入后的字符串
            room *= 2;
        }
        size_type new_size = std::max(room, std::ptrdiff_t(1));
        iterator new_data = alloc.allocate(new_size);

        std::uninitialized_copy(str, str + std::strlen(str),
                                std::uninitialized_copy(d, d + size(),new_data));

        uncreate();

        d = new_data;
        avail = new_data + new_length;
        limit = new_data + new_size;
    }else{
        std::uninitialized_copy(str, str + std::strlen(str),
                                d + size());
        avail = d + new_length;
    }
}

void Str_c::prepend(const char* str, const Str_c::size_type n) {
    size_type new_length = n + size() + 1;//加入的字符串的长度

    if(limit == avail || avail + n  >= limit){
        std::ptrdiff_t room = 2 * (limit - d);
        while(size_type(room) < new_length){
            room *= 2;
        }

        size_type new_size = std::max(room, std::ptrdiff_t(1));
        iterator new_data = alloc.allocate(new_size);

        std::uninitialized_copy(d, d + size(),
                                std::uninitialized_copy(str, str + std::strlen(str),new_data));

        uncreate();

        d = new_data;
        avail = new_data + new_length;
        limit = new_data + new_size;
    }else{
        std::uninitialized_copy(d, d + size(),
                                std::uninitialized_copy(str, str + std::strlen(str),d));
        avail = d + new_length;
    }
}

void Str_c::append(const char c) {
    append(&c, 1);
}

void Str_c::append(const Str_c &str) {
    append(str.d, str.size());
}

2.4.3 加法运算符

    friend Str_c operator+(const char* , const Str_c& );
Str_c operator+(const Str_c& s, const Str_c& t){
    Str_c r = s;
    r += t;
    return r;
}

Str_c operator+(const Str_c& s, const char* t){
    Str_c r = s;
    r += t;
    return r;
}

Str_c operator+(const char* t, const Str_c& s){
    Str_c r = s;
    r.prepend(t, strlen(t));
    return r;
}

2.4.4 比较操作符函数

inline bool operator==(const Str_c& l, const Str_c& r){
    return std::strcmp(l.c_str(),r.c_str()) == 0;
}

inline bool operator!=(const Str_c& l, const Str_c& r){
    return std::strcmp(l.c_str(),r.c_str()) != 0;
}

inline bool operator>(const Str_c& l, const Str_c& r){
    return std::strcmp(l.c_str(),r.c_str()) > 0;
}

inline bool operator>=(const Str_c& l, const Str_c& r){
    return std::strcmp(l.c_str(),r.c_str()) >= 0;
}

inline bool operator<(const Str_c& l, const Str_c& r){
    return std::strcmp(l.c_str(),r.c_str()) < 0;
}

inline bool operator<=(const Str_c& l, const Str_c& r){
    return std::strcmp(l.c_str(),r.c_str()) <= 0;
}

2.4.5 输入运算符

    friend std::istream&  operator>>(std::istream&, Str_c&);
std::istream& operator >>(std::istream& is, Str_c& s){
    s.clear();
    char c;
    //按序读字符并忽略前面的空格字符
    while(is.get(c) && isspace(c));
    //读入非空白字符
    if(is){
        do{
            s.append(c);
        }while(is.get(c) && !isspace(c));
    }
    //如果遇到一空格字符,将它放在输入流的后面
    if(is){
        is.unget();
    }
    return is;
}

2.4.6 输出运算符

std::ostream& operator<<(std::ostream& os, Str_c& s){
    std::copy(s.begin(), s.end(), std::ostream_iterator<char>(os));
    return os;
}

2.5 操作数函数

public:
    //操作函数
    operator void*() const{return is_not_empty();}
private:
	    //操作函数
    void* is_not_empty() const{ return  size() > 0 ? d : 0;}    

2.6 clear()

public:
    //清空
    void clear(){destory();}
private:
	    //clear
    void destory();    
void Str_c::destory() {
    uncreate();
    create(0,'\0');
}

2.7 insert()

public:
    //插入元素
    void insert(const_iterator , const_iterator , const_iterator);
    void insert(size_type pos, const Str_c& s);
void Str_c::insert(Str_c::const_iterator out, Str_c::const_iterator b, Str_c::const_iterator e) {
   ptrdiff_t dis = e - b;
    dis = size_type (dis);
    ptrdiff_t  pos = out - d;
    pos = size_type (pos);
    if(pos > size()) throw std::domain_error("");//插入位置非法

    size_type new_length = dis + size() + 1;//加入字符串后的长度
//    size_type container = size_type (limit - d);//容器长度包括未初始化的
    if(limit == avail || avail + dis  >= limit){
        ptrdiff_t room = 2 * (limit - d);
        while(size_type(room) < new_length){//直到分配的空间可以容纳加入后的字符串
            room *= 2;
        }
        size_type new_size = std::max(room, std::ptrdiff_t(1));
        iterator new_data = alloc.allocate(new_size);

        std::uninitialized_copy(d + pos,d +size(),std::uninitialized_copy(b,  e,
                                                                          std::uninitialized_copy(d, d + pos,new_data)));

        uncreate();

        d = new_data;
        avail = new_data + new_length;
        limit = new_data + new_size;
    }else{
        //暂存插入位置后面的内容
        char replica[size_type(avail - out)];
        std::copy(d + pos,d + size(), replica);

        std::uninitialized_copy(replica, replica + std::strlen(replica),std::uninitialized_copy(b, e, d + pos));
        avail = d + new_length;
    }
}

void Str_c::insert(Str_c::size_type pos, const Str_c &s) {
    const_iterator p = d + pos;
    insert(p, s.begin(),s.end());
}

2.8 c_str(),data()

public:
    //将其Str_c转换为其他类型
    const_iterator c_str() const{ return  data();};
    const_iterator data() const{ return d;}
public:
    //copy将int类型的参数指定的个数的字符复制到char*类型的内存中
    size_type copy(char* p, size_type n, size_type pos = 0) const { return copy_characters(p, n, pos);}
private:
	    //copy
    size_type copy_characters(char*, size_type, size_type)const;
size_t Str_c::copy_characters(char* s, Str_c::size_type n, Str_c::size_type pos = 0) const {
    size_type sz = size();
    //其实位置超过字符串的长度,扔出错误
    if(pos > size()) throw std::domain_error("Out of range!");
    //保证复制的范围不会超过字符串的最大长度
    size_type rlen = std::min(n, sz - pos);

    std::copy(d+ pos, d+pos+rlen, s);

    return rlen;
}

2.9 getline()

    friend std::istream& getline(std::istream&, Str_c& );
std::istream& getline(std::istream& is, Str_c& s){
    s.uncreate();
    s.create(0,'\0');

    char c;
    if(is){
        while (is.get(c) && c != '\n'){
            s.append(c);
        }
    }
    return  is;
}

2.10 汇总代码

头文件:

//
// Created by MacBook Pro on 2020-03-17.
//

#ifndef ACM_STR_C_H
#define ACM_STR_C_H

#include <cctype>
#include <memory>
#include <algorithm>
#include <iterator>
#include <cstring>
#include <exception>

class Str_c{
    friend std::istream&  operator>>(std::istream&, Str_c&);
    friend Str_c operator+(const char* , const Str_c& );
    friend std::istream& getline(std::istream&, Str_c& );
public:
    typedef size_t size_type;
    typedef char* iterator;
    typedef const char* const_iterator;

    //构造
    //默认构造
    Str_c(){create(0,'\0');}
    //复制构造
    Str_c(const Str_c& s){create(s.begin(), s.end());}
    //带参构造(长度、字符)
    Str_c(size_type n, char c){create(n,c);}
    //带参构造(迭代器始末)
    template<class In> Str_c( In b, In e){create(b,e);}
    //带参构造(类型转换)
    Str_c(const char* cp){create(cp, cp + std::strlen(cp));}
    //赋值运算符
    Str_c&  operator=(const Str_c&);
    Str_c&  operator=(const char*);
    //析构函数
    ~Str_c(){uncreate();}

    //索引运算符
    char& operator[](size_type i){ return d[i];}
    const char&operator[](size_type i) const{ return  d[i];}
    //复合加法赋值运算符
    Str_c& operator+=(const char* cp){
        append(cp, std::strlen(cp));
        return *this;
    }

    Str_c&operator+=(const Str_c& s){
        append(s);
        return *this;
    }
    //操作函数
    operator void*() const{return is_not_empty();}
    //清空
    void clear(){destory();}
    //插入元素
    void insert(const_iterator , const_iterator , const_iterator);
    void insert(size_type pos, const Str_c& s);
    //将其Str_c转换为其他类型
    const_iterator c_str() const{ return  data();};
    const_iterator data() const{ return d;}
    //copy将int类型的参数指定的个数的字符复制到char*类型的内存中
    size_type copy(char* p, size_type n, size_type pos = 0) const { return copy_characters(p, n, pos);}
    //字符串长度,不包括\0
    size_type size() const{ return avail - d - 1;}

    //始末迭代器
    iterator begin(){ return  d;}
    const_iterator begin() const{ return d;}
    iterator end() { return  d + size();}
    const_iterator end() const{ return d + size();}

private:
    char* d;//指向字符串的第一个字符的指针
    char* avail;//指向最后一个有值的字符后面两位的指针
    char* limit;//指向字符串的最后一个字符后面的指针
    std::allocator<char> alloc;

    //构造函数调用
    void create(size_type, char);
    template <class In> void create(In,In);
    //析构函数
    void uncreate();
    //clear
    void destory();
    //复合加法赋值运算符
    void append(const char*, const size_type);
    void append(const char);
    void append(const Str_c&);
    void prepend(const char*, const size_type);
    //copy
    size_type copy_characters(char*, size_type, size_type)const;
    //操作函数
    void* is_not_empty() const{ return  size() > 0 ? d : 0;}
};

void Str_c::create(Str_c::size_type n, char c) {
    d = alloc.allocate(n + 1);
    limit = avail = d + n + 1;
    std::uninitialized_fill(d, d + n, c);
//    alloc.construct(data + n, '\0');

}

template <class In>
void Str_c::create(In b, In e) {
    d = alloc.allocate(e - b + 1);//多分配一个长度存储空白字符
    limit = avail = std::uninitialized_copy(b, e, d) + 1;//指向e的后面两个为止(后面还多一个空白字符)
}

void Str_c::uncreate() {
    if(avail != 0){
        iterator it = avail;
        while(it != d){
            alloc.destroy(--it);
        }
        alloc.deallocate(d, limit - d);
    }
    d = avail = limit = 0;
}

void Str_c::append(const char* str, const Str_c::size_type n) {
    size_type new_length = n + size() + 1;//加入字符串后的长度

    if(limit == avail || avail + n  >= limit){
        ptrdiff_t room = 2 * (limit - d);
        while(size_type(room) < new_length){//直到分配的空间可以容纳加入后的字符串
            room *= 2;
        }
        size_type new_size = std::max(room, std::ptrdiff_t(1));
        iterator new_data = alloc.allocate(new_size);

        std::uninitialized_copy(str, str + std::strlen(str),
                                std::uninitialized_copy(d, d + size(),new_data));

        uncreate();

        d = new_data;
        avail = new_data + new_length;
        limit = new_data + new_size;
    }else{
        std::uninitialized_copy(str, str + std::strlen(str),
                                d + size());
        avail = d + new_length;
    }
}

void Str_c::prepend(const char* str, const Str_c::size_type n) {
    size_type new_length = n + size() + 1;//加入的字符串的长度

    if(limit == avail || avail + n  >= limit){
        std::ptrdiff_t room = 2 * (limit - d);
        while(size_type(room) < new_length){
            room *= 2;
        }

        size_type new_size = std::max(room, std::ptrdiff_t(1));
        iterator new_data = alloc.allocate(new_size);

        std::uninitialized_copy(d, d + size(),
                                std::uninitialized_copy(str, str + std::strlen(str),new_data));

        uncreate();

        d = new_data;
        avail = new_data + new_length;
        limit = new_data + new_size;
    }else{
        std::uninitialized_copy(d, d + size(),
                                std::uninitialized_copy(str, str + std::strlen(str),d));
        avail = d + new_length;
    }
}

void Str_c::append(const char c) {
    append(&c, 1);
}

void Str_c::append(const Str_c &str) {
    append(str.d, str.size());
}

Str_c& Str_c::operator=(const Str_c &s) {
    if(&s != this){
        uncreate();
        create(s.begin(),s.end());
    }
    return *this;
}

Str_c&  Str_c::operator=(const char *s) {
    uncreate();
    create(s, s + strlen(s));
    return *this;
}

std::istream& operator >>(std::istream& is, Str_c& s){
    s.clear();
    char c;
    //按序读字符并忽略前面的空格字符
    while(is.get(c) && isspace(c));
    //读入非空白字符
    if(is){
        do{
            s.append(c);
        }while(is.get(c) && !isspace(c));
    }
    //如果遇到一空格字符,将它放在输入流的后面
    if(is){
        is.unget();
    }
    return is;
}

std::ostream& operator<<(std::ostream& os, Str_c& s){
    std::copy(s.begin(), s.end(), std::ostream_iterator<char>(os));
    return os;
}


Str_c operator+(const Str_c& s, const Str_c& t){
    Str_c r = s;
    r += t;
    return r;
}

Str_c operator+(const Str_c& s, const char* t){
    Str_c r = s;
    r += t;
    return r;
}

Str_c operator+(const char* t, const Str_c& s){
    Str_c r = s;
    r.prepend(t, strlen(t));
    return r;
}

void Str_c::destory() {
    uncreate();
    create(0,'\0');
}

size_t Str_c::copy_characters(char* s, Str_c::size_type n, Str_c::size_type pos = 0) const {
    size_type sz = size();
    //其实位置超过字符串的长度,扔出错误
    if(pos > size()) throw std::domain_error("Out of range!");
    //保证复制的范围不会超过字符串的最大长度
    size_type rlen = std::min(n, sz - pos);

    std::copy(d+ pos, d+pos+rlen, s);

    return rlen;
}

inline bool operator==(const Str_c& l, const Str_c& r){
    return std::strcmp(l.c_str(),r.c_str()) == 0;
}

inline bool operator!=(const Str_c& l, const Str_c& r){
    return std::strcmp(l.c_str(),r.c_str()) != 0;
}

inline bool operator>(const Str_c& l, const Str_c& r){
    return std::strcmp(l.c_str(),r.c_str()) > 0;
}

inline bool operator>=(const Str_c& l, const Str_c& r){
    return std::strcmp(l.c_str(),r.c_str()) >= 0;
}

inline bool operator<(const Str_c& l, const Str_c& r){
    return std::strcmp(l.c_str(),r.c_str()) < 0;
}

inline bool operator<=(const Str_c& l, const Str_c& r){
    return std::strcmp(l.c_str(),r.c_str()) <= 0;
}

std::istream& getline(std::istream& is, Str_c& s){
    s.uncreate();
    s.create(0,'\0');

    char c;
    if(is){
        while (is.get(c) && c != '\n'){
            s.append(c);
        }
    }
    return  is;
}

void Str_c::insert(Str_c::const_iterator out, Str_c::const_iterator b, Str_c::const_iterator e) {
   ptrdiff_t dis = e - b;
    dis = size_type (dis);
    ptrdiff_t  pos = out - d;
    pos = size_type (pos);
    if(pos > size()) throw std::domain_error("");//插入位置非法

    size_type new_length = dis + size() + 1;//加入字符串后的长度
//    size_type container = size_type (limit - d);//容器长度包括未初始化的
    if(limit == avail || avail + dis  >= limit){
        ptrdiff_t room = 2 * (limit - d);
        while(size_type(room) < new_length){//直到分配的空间可以容纳加入后的字符串
            room *= 2;
        }
        size_type new_size = std::max(room, std::ptrdiff_t(1));
        iterator new_data = alloc.allocate(new_size);

        std::uninitialized_copy(d + pos,d +size(),std::uninitialized_copy(b,  e,
                                                                          std::uninitialized_copy(d, d + pos,new_data)));

        uncreate();

        d = new_data;
        avail = new_data + new_length;
        limit = new_data + new_size;
    }else{
        //暂存插入位置后面的内容
        char replica[size_type(avail - out)];
        std::copy(d + pos,d + size(), replica);

        std::uninitialized_copy(replica, replica + std::strlen(replica),std::uninitialized_copy(b, e, d + pos));
        avail = d + new_length;
    }
}

void Str_c::insert(Str_c::size_type pos, const Str_c &s) {
    const_iterator p = d + pos;
    insert(p, s.begin(),s.end());
}
#endif //ACM_STR_C_H


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

繁星蓝雨

如果觉得文章不错,可以请喝咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值