String C++实现

改进:

/*
版权信息:狼
文件名称:String.h
文件标识:
摘 要:对于上版本简易的String进行优化跟进。
改进
1.(将小块内存问题与大块分别对待)小内存块每个对象都有,当内存需求大于定义大小时利用动态分配
2.实现大块内存的写时拷贝功能,提高效率,优化空间利用
3.类似new[]实现机制:将动态内存块大小信息保存为隐藏“头”
4.对于大块内存采取动态增长型。不够时扩容为当前大小的2倍 当前版本:1.2
修 改 者:狼
完成日期:2015-12-12 取代版本:1.1
原 作 者:狼
完成日期:2015-12-11
*/
#ifndef _STRING_H
#define _STRING_H
#include<iostream>
using namespace ::std; namespace COW
{
class String
{
friend void Check_Interface(String &S);
friend ostream& operator << (ostream&os, String &Str); public:
String(const char* str = "");
String(String& Str);
String& operator=(const String& Str);
~String(); public:
int Find(char ch)const;
int Find(const char* str)const;
void PushBack(char ch);
void Insert(size_t pos, char ch);
void Insert(size_t pos, const char* str);
bool Erase(size_t pos);
bool Erase(size_t pos, size_t n);
size_t Strlen()const; private:
void InitInfo(size_t inUse); //初始化capacity and inUse
void CheckMem(size_t add = ); //对于内存操作时的增否处理
const char* GetAdd()const; //获取当前字符串所在位置
size_t capacity()const; //读取头,获得有效容量长度
int inCount()const; //获取引用计数
void decrease();//减少引用计数。
void increase();//增加引用计数。 private:
enum{BufSize = }; //利用枚举进行数组初始化
char *_str; //内容块,“头”代替capacity
char _buff[BufSize]; // 小内存块处理。
};
ostream& operator << (ostream&os, String &Str);
}
#endif #include"String.h"
#pragma warning (disable:4351 4996) using namespace COW; String::String(const char *Str)
:_str(NULL)
, _buff()
{
//采用动态分配
if (strlen(Str) >= BufSize)
{
//1.记录引用计数,2.记录当前有效大小 strlen()+1
_str = new char[strlen(Str) + +]; InitInfo(strlen(Str)+); char *cur = const_cast<char*>(GetAdd());
strcpy(cur, Str); //有效位置
}
else//静态存储
{
strcpy(_buff, Str);
}
}
String::String(String& Str)
:_str(NULL)
, _buff()
{
// 1.如果是小块内存。浅拷贝
if (Str._str == NULL)
{
strcpy(_buff,Str._buff);
}
else
{
_str = Str._str;
this->increase();
}
}
String& String::operator=(const String& Str)
{
//都是动态 且指向一处
if (_str == Str._str&&_str != NULL)
return *this; //两个都是小内存时
if (Str._str == NULL&&_str==NULL)
{
strcpy(_buff, Str._buff);
}
//如果*this 是小内存(不存在内存变更,不用处理buff),Str 动态。
else if (_str==NULL&&Str._str!=NULL)
{
_str = Str._str;
this->increase();
} //*this 动态,Str小内存。减少*this._str计数。。.更改buff
else if(_str!=NULL&&Str._str==NULL)
{
this->decrease();
_str = NULL;
strcpy(_buff,Str._buff);
} //两个都是动态分配 但不同
else
{
this->decrease();
_str = Str._str;
this->increase();
}
return *this;
}
///////问题1...命名空间冲突时
ostream& COW::operator << (ostream&os, String &Str)
{
if (Str._str)
{
os << (Str._str + );
}
else
os << Str._buff;
return os;
} ////////////////////////core_func
inline void String::increase()
{
*(int*)_str += ;
} inline void String::decrease()
{
if (_str != NULL)
{ //////问题2,,每次decrease之后必须变更_str..为NULL或者指向新块
if ((*(int*)_str) - != )
{
(*(int*)_str) -= ;
}
else
{
delete[]_str;
_str = NULL;
}
}
}
String::~String()
{
this->decrease();
_str = NULL;
} ///获取字符串的核心地址
const char *String::GetAdd()const
{
//忘记给对正确起始点
return _str ? _str+ : _buff;
} size_t String::capacity()const
{
return *((int*)_str+);
}
int String::inCount()const
{
return *((int*)_str);
} //设置头 信息
void String::InitInfo(size_t inUse)
{
*((int*)_str) = ;
*((int*)_str + ) = inUse;
} void String::CheckMem(size_t add)
{
if (_str == NULL)
{
//小内存,且变动后不越界。
if (strlen(_buff) + add < )
return;
//小内存,变动后越界
else
{
_str = new char[strlen(_buff) + add + ]; InitInfo(strlen(_buff) + add+);
}
}
else
{
//容量足够,且引用计数为1;
if (strlen(_str + ) + add < capacity()&& inCount()==)
{
//,但是写时拷贝,需要更新空间,所以顺带增加宽度
//if (inCount() != 1)
//{
// int new_mem = (strlen(_str + 8) + add) * 2 + 9;
// this->decrease();
//
// _str = new char[new_mem];
// //少了+1 会造成后续始终有一个字节浪费问题
// InitInfo((strlen(_str + 8) + add) * 2 + 1);
//}
return;
}
else
{
//扩容后,容量为当前串长的2倍。 匹配使用,,用realloc 会出现问题
//realloc(_str, (strlen(_str+8) + add) * 2 + 8); //不能delete,,写时拷贝忘记了。。引用计数问题忘记了?
//delete[] _str;、
//先计算所需,再decrease(),因为可能赋值为NULL,不得求Strlen
int new_mem = (strlen(_str + ) + add) * + ;
this->decrease();
_str = new char[new_mem]; //少了+1 会造成后续始终有一个字节浪费问题
InitInfo(new_mem-);
}
}
} //////////////////publicFunc
int String::Find(char ch)const
{
char *cur = const_cast<char*>(GetAdd());
int pos = -;
while (*cur)
{
pos++;
if (*cur == ch)
return pos;
cur++;
}
return -;
} int String::Find(const char* str)const
{
if (str == NULL)
return -;
char *cur = const_cast<char*>(GetAdd());
int pos = -;
int len = strlen(str);
while (*(cur + len))
{
pos++;
///简直,,if 后边有个;bug
if (strncmp(cur, str, len) == )
return pos;
cur++;
}
return -;
}
void String::PushBack(char ch)
{
//首先保存内容。然后判断空间,然后存储。
char p[];
char *st = const_cast<char*>(GetAdd()); strcpy(p, st); CheckMem(); //默认为1; st = const_cast<char*>(GetAdd());
strcpy(st, p); st[strlen(st)+] = '\0';
st[strlen(st)] = ch; } size_t String::Strlen()const
{
return strlen(GetAdd());
} void String::Insert(size_t pos, char ch)
{
//越界有效化。。。
if (pos >= Strlen())
{
pos = Strlen()-;
}
//首先保存内容。然后判断空间,然后存储。
char p[];
char *st = const_cast<char*>(GetAdd()); strcpy(p, st); CheckMem(); //默认为1; st = const_cast<char*>(GetAdd());
strncpy(st, p, pos); st[pos] = ch; //不能用strcat,前边字符串不存在'\0'
strcpy(st + pos + , p + pos);
} void String::Insert(size_t pos, const char* str)
{
//越界有效化。。。
if (pos >= Strlen())
{
pos = Strlen();
}
//首先保存内容。然后判断空间,然后存储。
char p[];
char *st = const_cast<char*>(GetAdd()); strcpy(p, st); int len = strlen(str);
CheckMem(len); //默认为1; st = const_cast<char*>(GetAdd());
strncpy(st, p, pos); strcpy(st + pos, str); strcpy(st + pos + len, p + pos);
} bool String::Erase(size_t pos)
{
char *cur = const_cast<char*>(GetAdd());
size_t len = Strlen();
if (pos >= len)
return false;
memmove(cur+ pos, cur + pos + , len + );
return true;
} bool String::Erase(size_t pos, size_t n)
{
char *cur = const_cast<char*>(GetAdd());
size_t len = strlen(cur + pos + );
if (pos >= len)
return false;
memmove(cur + pos, cur + pos + n, len + );
return true;
} //////friend 友员函数不能跨越命名空间访问私有成员????????????
void Check_Interface(COW::String &S)
{
//char COW::String::*ch = S._str;
//const char *ch = S._str;
cout << endl;
} ///////////////////////////Test
#include"String.h"
using namespace COW; void Test_COPY_EPU()
{ String S1("hellow world!");
String S2("hellow world");
String S3;
S3 = S2;
String S4;
S4 = S1;
//少对多,少对少
cout << "小内存赋值" << S3 << endl;
cout << "小内存赋值" << S4 << endl; //多对多,多对少
String S5("change world");
S5 = S1;
cout << S5 << endl;
S5 = S2;
cout << S5 << endl;
//多多且等
String S6 = S1;
S6 = S1;
cout << S6 << endl;
}
void Test_Find_Erase()
{
String S1("hellow world!");
String S2("hellow world");
cout << S1.Find('l') << endl;
cout << S2.Find('z') << endl;
cout << S1.Find("low") << endl;
char*p = NULL;
cout << S2.Find(p) << endl; S2.Erase();
S2.Erase(, );
cout << S2 << endl;
} void Test_Push_Insert()
{
String S1("hellow world!");
String S2("hellow world");
//S1.PushBack('l');
//S1.PushBack('v');
//S2.PushBack('l');
//S2.PushBack('v');
int pos = S1.Find('l');
S1.Insert(pos,'v');
S1.Insert(, "lv");
cout << S1 << endl;
cout << S2 << endl; }
void main()
{
//Test_COPY_EPU();
//Test_Find_Erase();
Test_Push_Insert();
}

String C++完整实现。的更多相关文章

  1. es string 分词完整示例

    "products_name_en": {            "type":  "string", //字符串类型            ...

  2. C++11:新式的字符串字面常量(String Literal)

    自C++11起,我们可以定义 raw string 字符串字面常量. Raw string 允许我们定义所见即所得的字符串字面常量,从而可以省下很多用来修饰特殊 字符的符号. Raw string 以 ...

  3. python select网络编程详细介绍

    刚看了反应堆模式的原理,特意复习了socket编程,本文主要介绍python的基本socket使用和select使用,主要用于了解socket通信过程 一.socket模块 socket - Low- ...

  4. python之网络编程

    本地的进程间通信(IPC)有很多种方式,但可以总结为下面4类: 消息传递(管道.FIFO.消息队列) 同步(互斥量.条件变量.读写锁.文件和写记录锁.信号量) 共享内存(匿名的和具名的) 远程过程调用 ...

  5. python网络编程-socket

    python提供了两个socket模块 Socket,它提供了标准的BSD Sockets API SocketServer,它提供了服务器中心类,可以简化网络服务器的开发 下面先说socket模块 ...

  6. [转]JSON 入门指南

    原文地址:http://www.ibm.com/developerworks/cn/web/wa-lo-json/ 尽管有许多宣传关于 XML 如何拥有跨平台,跨语言的优势,然而,除非应用于 Web ...

  7. hibernate----(Hql)查询

    package com.etc.test; import java.util.List;import java.util.Properties; import org.hibernate.Query; ...

  8. Python中的socket 模块

    Python 提供了两个基本的 socket 模块.第一个是 Socket,它提供了标准的 BSD Sockets API.第二个是 SocketServer, 它提供了服务器中心类,可以简化网络服务 ...

  9. ado.net 实体类_数据访问类

    实体类: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ...

随机推荐

  1. KDDCUP CTR预测比赛总结

    赛题与数据介绍 给定查询和用户信息后预测广告点击率 搜索广告是近年来互联网的主流营收来源之一.在搜索广告背后,一个关键技术就是点击率预测-----pCTR(predict the click-thro ...

  2. 如何确定LDA的主题个数

    本文参考自:https://www.zhihu.com/question/32286630 LDA中topic个数的确定是一个困难的问题. 当各个topic之间的相似度的最小的时候,就可以算是找到了合 ...

  3. 工作笔记——js前端规范

    去年年末做了一个项目,因为第一次做前端管理职位,第一次做整个项目的前端架构很多东西都不熟悉,作为一次大胆的尝试. js方面的只有一个坑,那就是前端与后端的网络层封装,这一块是在后端的协助下开发的.网络 ...

  4. 存储器系列,L1缓存,L2缓存,内存(RAM),EEPROM和闪存,CMOS与BIOS电池

    因为各级存储硬件的参数和性能不同所以在计算机硬件当中分为以下几种: 由此可见顶级空间小但处理速度最快,下层容量大但处理速度时间较长. 存储器系统采用分层结构,顶层的存储器速度较高,容量较小,与底层的存 ...

  5. 数据库(11)-- Hash索引和BTree索引 的区别

    索引是帮助mysql获取数据的数据结构.最常见的索引是Btree索引和Hash索引. 不同的引擎对于索引有不同的支持:Innodb和MyISAM默认的索引是Btree索引:而Mermory默认的索引是 ...

  6. javascript面向对象笔记(一)

    ECMAscript对象(以下简称对象): ECMA-262把对象定义为:无序属性的集合,其属性可以包含基本值.对象或者函数. 对象的每个属性或方法都有一个名字,而每个名字都映射到一个值.值可以是数据 ...

  7. 关于Socket和ServerSocket类详解

    Socket类 套接字是网络连接的一个端点.套接字使得一个应用可以从网络中读取和写入数据.放在两个不同计算机上的两个应用可以通过连接发送和接受字节流.为了从你的应用发送一条信息到另一个应用,你需要知道 ...

  8. JQuery归纳总结(增加中...)

    一.this与$(this)的区别 this指向标签本身对象,而$(this)会将其封装成JQuery对象 如: $(" img").mousemove( function(e){ ...

  9. Apple 的命令行交付工具“Transporter”

    Apple 的命令行交付工具“Transporter” 占坑... https://help.apple.com/itc/transporteruserguide/#/apdATD1E1026-D1E ...

  10. 伪类 :after 清除浮动的原理和方法

    浮动元素容器的clearing问题1. 问题的由来有这样一种情形:在一个容器(container)中,有两个浮动的子元素.<div>        <div style=" ...