C++primer 练习13.39
13.39 编写你自己版本的StrVec,包括自己版本的reserve,capacity(参见9.4节,第318页)和resize(参见9.3.5节,第314页)
13.40 为你的StrVec类添加一个构造函数,它接受一个initializer_list<string>参数
这是StrVec.h
#pragma once #include<string>
#include<memory>
#include<initializer_list>
using namespace std; class StrVec
{
public:
StrVec():
elements(nullptr),first_free(nullptr),cap(nullptr){}
StrVec(initializer_list<string> iLStr);//构造函数,接受一个initializer_list<string>参数
StrVec(const StrVec&);
StrVec& operator=(const StrVec&);
~StrVec();
string& operator[](size_t n)const //重载下标运算符,用来实现TextQuery和QueryResult对StrVec的使用
{
return *(elements + n);
}
void push_back(const string&);
size_t size()const { return first_free - elements; }
size_t capacity()const { return cap - elements; }
string *begin()const { return elements; }
string *end()const { return first_free; }
void reserve(size_t n);//分配至少容纳n个元素的空间
void resize(size_t n);//调整容器的大小为n个元素。若n<size(),则多出的元素被丢弃
//若必须添加新元素,对新元素进行值初始化
void resize(size_t n,string str);//调整容器的大小为n个元素,任何新添加的元素都初始化为值str
private:
allocator<string> alloc;
void chk_n_alloc()
{
if (size() == capacity())
reallocate();
}
pair<string*, string*>alloc_n_copy(const string *, const string *);
void free();
void reallocate();
string *elements;
string *first_free;
string *cap;
}; void StrVec::push_back(const string &s)
{
chk_n_alloc();
alloc.construct(first_free++, s);
} pair<string*,string*>
StrVec::alloc_n_copy(const string *b, const string *e)
{
auto data = alloc.allocate(e - b);
return{ data,uninitialized_copy(b,e,data) };
} void StrVec::free()
{
if (elements) {
for (auto p = first_free;p != elements;)
alloc.destroy(--p);
alloc.deallocate(elements, cap - elements);
}
} StrVec::StrVec(const StrVec &s)
{
auto newdata = alloc_n_copy(s.begin(), s.end());
elements = newdata.first;
first_free = cap = newdata.second;
} StrVec::~StrVec() { free(); } StrVec &StrVec::operator=(const StrVec &rhs)
{
auto data = alloc_n_copy(rhs.begin(), rhs.end());
free();
elements = data.first;
first_free = cap = data.second;
return *this;
} void StrVec::reallocate()
{
auto newcapacity = size() ? * size() : ;
auto newdata = alloc.allocate(newcapacity);
auto dest = newdata;
auto elem = elements;
for (size_t i = ;i != size();++i)
alloc.construct(dest++, move(*elem++));
free();
elements = newdata;
first_free = dest;
cap = elements + newcapacity;
} void StrVec::reserve(size_t n)//分配至少容纳n个元素的空间
{
if (n > capacity())//如果n大于capacity()才会从新分配空间
{
auto newdata = alloc.allocate(n);//重新分配n个空间,newdata为新分配的空间的首地址
auto dest = newdata;
auto elem = elements;
for (;elem != first_free;) //为新分配的空间调用construct来实现string的构造,采用move调用的是移动构造函数
alloc.construct(dest++, move(*(elem++)));
free(); //元素的移动完成,释放原有的空间
elements = newdata; //为指针赋予新的值
first_free = dest;
cap = elements + n;
}
else return;
} void StrVec::resize(size_t n)//调整容器的大小为n个元素。若n<size(),则多出的元素被丢弃
//若必须添加新元素,对新元素进行值初始化
{
if (n <= size()) //如果n<size()则,应该对n后面的所有已经构造的元素调用destroy(),即多出的元素被丢弃
{
for (;first_free != elements + n;)
alloc.destroy(--first_free);
}
else
{
if (n > capacity())
{
reserve(n); //因为n>capacity(),所以一定会分配新的空间
}
for (;first_free != elements + n;) //添加新的元素,对新的元素进行值初始化
alloc.construct(first_free++, string(""));
}
} void StrVec::resize(size_t n,string str)//调整容器的大小为n个元素,任何新添加的元素都初始化为值str {
if (n <= size()) //如果n<size()则,应该对n后面的所有已经构造的元素调用destroy(),即多出的元素被丢弃
{
for (;first_free != elements + n;)
alloc.destroy(--first_free);
}
else
{
if (n > capacity())
{
reserve(n); //因为n>capacity(),所以一定会分配新的空间
}
for (;first_free != elements + n;) //添加新的元素为str
alloc.construct(first_free++, str);
}
} StrVec::StrVec(initializer_list<string> iLStr)//构造函数,接受一个initializer_list<string>参数
{
auto newdata = alloc_n_copy(std::begin(iLStr), std::end(iLStr));//调用alloc_n_copy函数,返回一个pair<string*,string*>
elements = newdata.first; //pair的第一个元素为新分配空间的地址
first_free = cap = newdata.second; //pair的第二个元素为新分配空间的最后一个元素之后的地址
}
下面是主函数,用来验证程序的正确性
// 13.5.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#define _SCL_SECURE_NO_WARNINGS
#include"StrVec.h"
#include<string>
#include<iostream>
#include<memory>
using namespace std; int main()
{
StrVec sv({ "li","dandan","is" });
cout << sv.size() << " " << sv.capacity() << endl;
sv.resize(, "handsome");
cout << sv.size() << " " << sv.capacity() << endl;
sv.resize();
cout << sv.size() << " " << sv.capacity() << endl;
sv.resize();
cout << sv.size() << " " << sv.capacity() << endl;
sv.reserve();
sv.push_back("handsome");
cout << sv.size() << " " << sv.capacity() << endl;
return ;
}
C++primer 练习13.39的更多相关文章
- C++primer 练习13.44
13.44:编写标准库string类的简化版本,命名为String.你的类应该至少有一个默认构造函数和一个接受C 风格字符串指针参数的构造函数.使用allocator为你的String类分配所需内存 ...
- 【C++ Primer 第13章】2. 拷贝控制和资源管理
拷贝控制和资源管理 • 类的行为像一个值.意味着它应该有自己的状态,当我们拷贝一个像值得对象时,副本和原对象是完全独立的,改变副本不会对原对象有任何影响. • 行为像指针的类则共享状态.当我们拷贝一个 ...
- 【C++ Primer 第13章】1. 拷贝控制、赋值和销毁
拷贝控制.赋值和销毁 如果一个构造函数的第一个参数是自身类的引用,且额外的参数都有默认值,则此构造函数是拷贝控制函数(拷贝构造函数不应该是explicit的). 如果我们没有为一个类定义拷贝构造函数, ...
- 【C++ Primer 第13章】3. 交换操作
交换操作 class HasPtr { friend void swap(HasPtr &rhs, HasPtr &yhs); //其他成员定义 }; void swap(HasPtr ...
- [C++ Primer] : 第13章: 拷贝控制
拷贝, 赋值与销毁 当定义一个类时, 我们显示地或隐式地指定在此类型的对象拷贝, 移动, 赋值和销毁时做什么. 一个类通过定义5种特殊的成员函数来控制这些操作, 包括: 拷贝构造函数, 拷贝赋值运算符 ...
- C++ primer chapter 13
拷贝 赋值 销毁 拷贝构造函数 如果一个构造函数第一个参数是自身的引用,而且任何额外参数都有默认值,则此构造函数是拷贝构造函数拷贝构造函数的第一个类型必须是引用:如果参数不是引用类型,那么调用不会成功 ...
- C++primer 练习13.36
#pragma once #include<string> #include<set> using namespace std; class Message { friend ...
- 【C++ Primer 第13章】6.对象移动
右值引用 左值和右值 (1)两者区别: ①左值:能对表达式取地址.或具名对象/变量.一般指表达式结束后依然存在的持久对象. ②右值:不能对表达式取地址,或匿名对象.一般指表达式结束就不再存在的临时对象 ...
- 【C++ Primer 第13章】5. 动态内存管理类
StrVec类的设计 [题目描述]:我们将实现标准库vector类的一个简化版本,我们所做的一个简化是不使用模板,我们类只用于string,因此,它被命名为StrVec. #include<io ...
随机推荐
- curl命令使用大全
curl命令使用大全 可以看作命令行浏览器 1.开启gzip请求curl -I http://www.sina.com.cn/ -H Accept-Encoding:gzip,defalte 2.监控 ...
- 一步一步理解Paxos算法
一步一步理解Paxos算法 背景 Paxos 算法是Lamport于1990年提出的一种基于消息传递的一致性算法.由于算法难以理解起初并没有引起人们的重视,使Lamport在八年后重新发表到 TOCS ...
- html之head,base,meta,title
一个简单的HTML最基本的必须的元素 用于定义文档的头部,是所有头部元素的容器.头部描述了文档的各种属性和信息,绝大多数头部的数据都不会直接显示给读者. 下面这些标签可用在head部分:base,li ...
- AngularJS初始化普通数组和对象数组
普通数组: ng-init="persons=['john','jack']" 对象数组: ng-init="persons=[{name:'john',age:20}, ...
- Presto集群安装配置
Presto是一个运行在多台服务器上的分布式系统. 完整安装包括一个coordinator(调度节点)和多个worker. 由客户端提交查询,从Presto命令行CLI提交到coordinator. ...
- 解决SQLite3数据库Error: database disk image is malformed
这种错误的提示一般都是数据库文件出现了问题,具体导致问题的原因不必深究,我们只讨论这种问题的饿解决方法: 比如数据库:test.db 这里还要分两种情况: 情况一: sqlite3 test.db & ...
- 多线程要点--CLR C#学习笔记
1.windows永远不会调度一个进程,只调度线程. 2.线程和操作系统的关系:CLR(X)--AppDomain--线程池(包含工作者线程和I/O线程) 3.线程的关键组成部分 A.线程执行上下文 ...
- C#.NET ,微信退款证书
微信退款时遇到:基础连接已经关闭 连接被意外关闭. 服务器环境:WIN SERVER 2008 R2. WINDOWS服务承载的WCF服务,基于.NET FRAMEWORK 3.5. 第一笔交易的退 ...
- 【Mongodb】3.0 配置身份验证db.createUser()说明
原文地址:http://bbs.51cto.com/thread-1146654-1.html 定义: 创建一个数据库新用户用db.createUser()方法,如果用户存在则返回一个用户重复错误. ...
- 关于c语言中qsort函数的一点心得
今天写c时无意间用到了排序,便想着使用c语言标准库中提供的排序函数,即qsort函数(c++stl中提供了sort函数用于排序),首先是介绍qsort函数的一些基本用法(以下内容转自: http:// ...