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的更多相关文章

  1. C++primer 练习13.44

    13.44:编写标准库string类的简化版本,命名为String.你的类应该至少有一个默认构造函数和一个接受C 风格字符串指针参数的构造函数.使用allocator为你的String类分配所需内存 ...

  2. 【C++ Primer 第13章】2. 拷贝控制和资源管理

    拷贝控制和资源管理 • 类的行为像一个值.意味着它应该有自己的状态,当我们拷贝一个像值得对象时,副本和原对象是完全独立的,改变副本不会对原对象有任何影响. • 行为像指针的类则共享状态.当我们拷贝一个 ...

  3. 【C++ Primer 第13章】1. 拷贝控制、赋值和销毁

    拷贝控制.赋值和销毁 如果一个构造函数的第一个参数是自身类的引用,且额外的参数都有默认值,则此构造函数是拷贝控制函数(拷贝构造函数不应该是explicit的). 如果我们没有为一个类定义拷贝构造函数, ...

  4. 【C++ Primer 第13章】3. 交换操作

    交换操作 class HasPtr { friend void swap(HasPtr &rhs, HasPtr &yhs); //其他成员定义 }; void swap(HasPtr ...

  5. [C++ Primer] : 第13章: 拷贝控制

    拷贝, 赋值与销毁 当定义一个类时, 我们显示地或隐式地指定在此类型的对象拷贝, 移动, 赋值和销毁时做什么. 一个类通过定义5种特殊的成员函数来控制这些操作, 包括: 拷贝构造函数, 拷贝赋值运算符 ...

  6. C++ primer chapter 13

    拷贝 赋值 销毁 拷贝构造函数 如果一个构造函数第一个参数是自身的引用,而且任何额外参数都有默认值,则此构造函数是拷贝构造函数拷贝构造函数的第一个类型必须是引用:如果参数不是引用类型,那么调用不会成功 ...

  7. C++primer 练习13.36

    #pragma once #include<string> #include<set> using namespace std; class Message { friend ...

  8. 【C++ Primer 第13章】6.对象移动

    右值引用 左值和右值 (1)两者区别: ①左值:能对表达式取地址.或具名对象/变量.一般指表达式结束后依然存在的持久对象. ②右值:不能对表达式取地址,或匿名对象.一般指表达式结束就不再存在的临时对象 ...

  9. 【C++ Primer 第13章】5. 动态内存管理类

    StrVec类的设计 [题目描述]:我们将实现标准库vector类的一个简化版本,我们所做的一个简化是不使用模板,我们类只用于string,因此,它被命名为StrVec. #include<io ...

随机推荐

  1. css之padding,marging

    padding:内边距,所有浏览器都支持,不允许使用负值 继承内部格式生成了10px的边距. 属性: auto:浏览器计算机内边距. length:规定以具体单位计的内边距值,比如像素.厘米等.默认值 ...

  2. maven设置---Dmaven.multiModuleProjectDirectory system propery is not set.

    设置maven 环境变量: MAVEN_HOME:D:\Java\apache-maven-3.3.3 M2_HOME:D:\Java\apache-maven-3.3.3 path:%MAVEN_H ...

  3. hadoop(三):hdfs 机架感知

    client 向 Active NN 发送写请求时,NN为这些数据分配DN地址,HDFS文件块副本的放置对于系统整体的可靠性和性能有关键性影响.一个简单但非优化的副本放置策略是,把副本分别放在不同机架 ...

  4. 如何在ExtJS 6中使用Fashion美化应用程序

    在Ext JS 6,一个最大的改变就是框架合并,使用一个单一的代码库,就可以为每一种设备开发各具有良好体验的最好应用程序.它还带来了一种美化应用程序的新方式. 在本文,重点是Sencha Fashio ...

  5. SOCKET:SO_LINGER 选项

    好多次接触到SO_LINGER选项,但总是忘了这是干什么用的.现在整理一下,我才明白这个参数是用来设定“SOCKET在CLOSE时候是否等待缓冲区发送完成”这个特性的.下面是一些详细的说明. sets ...

  6. bzoj3917: [Baltic2014]sequence

    Description  序列A由从N开始的连续K个数按顺序构成,现在将A中的每个数只保留某一个数码,记为序列B,给定K和B,求可能的最小的N Input 第一行一个数K,第二行K个数B_i Outp ...

  7. Java-输入输出

    1. 流的分类 java.io 1.1 输入和输出流 File类不能访问文件内容本身,需要使用输入/输出流 输入输出流的方向是相对与内存读写的方向. 1.2 字节流和字符流 字节流 InputStea ...

  8. SVN Server配置详解 及备份

    SVN简介和工作原理 subversion(简称svn)是近几年崛起的版本管理软件,是cvs的接班人,目前绝大多数开源软件都使用svn作为代码版本管理软件.Subversion支持linux和wind ...

  9. 反转(开关问题) POJ 3276

    POJ 3276 题意:n头牛站成线,有朝前有朝后的的,然后每次可以选择大小为k的区间里的牛全部转向,会有一个最小操作m次使得它们全部面朝前方.问:求最小操作m,再此基础上求k. 题解:1.5000头 ...

  10. Jedis 连接redis超时

    redis默认不允许远程连接 用vi打开Redis服务器的配置文件redis.conf ~ sudo vi /etc/redis/redis.conf #注释bind #bind 127.0.0.1 ...