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. TKinter布局之pack

    pack布局非常简单,不用做过多的设置,直接使用一个 pack 函数就可以了. 1.我们使用 pack 函数的时候,默认先使用的放到上面,然 后 依次向下排,它会给我们的组件一个自认为合适的位置 和大 ...

  2. SqlServer数据库正在还原的解决办法

    1)管理器不会主动刷新,需要手工刷新一下才能看到最新状态(性能方面的考虑) 2)很少情况下,恢复进程被挂起了.这个时候假设你要恢复并且回到可访问状态,要执行:  RESTORE database   ...

  3. 配置samba服务器

    公司需要一台用于共享的文件服务器,考虑使用Linux系统,听说会比windows的文件系统好管理,了解不多,人云亦云了! 这里需要用到samba系统,安装比较简单,安装后需要进行配置才能访问. 修改s ...

  4. linux shell 整理收集(不断更新)

    1)主从复制延时判断 (转 http://www.cnblogs.com/gomysql/p/3862018.html) 说明: 不要通过Seconds_Behind_Master去判断,该值表示sl ...

  5. Android Virtual Device(AVD)屏幕大小调整

    (1)各种常用机型的分辨率列表如下: WXGA800                 480X800 WVGA854                 480X854 WXGA720          ...

  6. session.flush加锁测试.

    测试结论 1 session.flush (用于提交SQL执行计划. hibernate会给数据库加锁, 执行效果等同于select for update的锁级别.如果是oracle 默认为lock ...

  7. SPOJ #692. Fruit Farm

    Another palindrome related problem. Actually nothing too theoretical here, but please keep following ...

  8. android学习笔记19——对话框(DatePickerDialog、TimePickerDialog)

    DatePickerDialog.TimePickerDialog ==> DatePickerDialog.TimePickerDialog功能.用法都比较简单,操作步骤: 1.通过new关键 ...

  9. [dts]Device Tree机制

    转自:http://blog.csdn.net/machiner1/article/details/47805069 ------------------Based on linux 3.10.24 ...

  10. 黄聪:wordpress/wp-includes目录文件

    wp-includes/cache.php wp-includes/capabilities.php wp-includes/class-IXR.php:Incutio XML-RPC库.包括了 XM ...