1. 目标

实现标准库vector类的一个简化版本,只支持string,我们命名为StrVec。

2. 设计思想

2.1 allocator管理每个StrVec对象的内存池, 是一块连续的内存(类型为元素的数组)。用于构建存储插入的元素

push_back插入元素, 检查内存池是否够用?. 够用,在内存池的下—可用位置构造对象·. 不够用,重组空间: . allocator获取全新的更大的内存池. 将已有元素拷贝至新的内存池. 释放旧的内存池. 在新内存池的下—可用位置构造新加入的元素

2.2 四个工具函数:

alloc_n_copy 会分配内存,并拷贝一个给定范围中的元素。
free 会销毁构造元素并释放内存。
chk_n_alloc 保证 StrVec 至少有容纳一个新元素的空间,如果没有空间添加新元素,chk_n_alloc 会调用 reallocate 类分配更多的内存。
reallocate 在内存用完时为 StrVec 分配新的内存。

3. StrVec.h

class StrVec {public:// copy control membersStrVec(): elements(nullptr), first_free(nullptr), cap(nullptr) { }StrVec(const StrVec&);            // copy constructorStrVec &operator=(const StrVec&); // copy assignment#ifdef NOEXCEPTStrVec(StrVec&&) noexcept;            // move constructorStrVec &operator=(StrVec&&) noexcept; // move assignment~StrVec() noexcept;                   // destructor
#elseStrVec(StrVec&&) throw();            // move constructorStrVec &operator=(StrVec&&) throw(); // move assignment~StrVec() throw();                   // destructor
#endif#ifdef INIT_LIST// additional constructorStrVec(std::initializer_list<std::string>);
#else // define a constructor that takes pointers to a range of elementsStrVec(const std::string*, const std::string*);
#endifvoid push_back(const std::string&);  // copy the elementvoid push_back(std::string&&);       // move the element// add elementssize_t size() const { return first_free - elements; }size_t capacity() const { return cap - elements; }// iterator interfacestd::string *begin() const { return elements; }std::string *end() const { return first_free; }#ifdef INIT_LIST   // no real substitute for initializer_list in assignments// operator functions covered in chapter 14StrVec &operator=(std::initializer_list<std::string>);
#endifstd::string& operator[](std::size_t n) { return elements[n]; }const std::string& operator[](std::size_t n) const { return elements[n]; }#ifdef VARIADICS    // no direct substitute for variadic functions// emplace member covered in chapter 16template <class... Args> void emplace_back(Args&&...);
#endif
private:static std::allocator<std::string> alloc; // allocates the elements// utility functions://  used by members that add elements to the StrVecvoid chk_n_alloc() { if (size() == capacity()) reallocate(); }// used by the copy constructor, assignment operator, and destructorstd::pair<std::string*, std::string*> alloc_n_copy(const std::string*, const std::string*);void free();             // destroy the elements and free the spacevoid reallocate();       // get more space and copy the existing elementsstd::string *elements;   // pointer to the first element in the arraystd::string *first_free; // pointer to the first free element in the arraystd::string *cap;        // pointer to one past the end of the array
};#include <algorithm>inline
#ifdef NOEXCEPT
StrVec::~StrVec() noexcept { free(); }
#else
StrVec::~StrVec() throw() { free(); }
#endif

4. StrVec.cpp

inline
std::pair<std::string*, std::string*>
StrVec::alloc_n_copy(const std::string *b, const std::string *e)
{// allocate space to hold as many elements as are in the rangeauto data = alloc.allocate(e - b); // initialize and return a pair constructed from data and// the value returned by uninitialized_copy
#ifdef LIST_INITreturn {data, uninitialized_copy(b, e, data)};
#elsereturn make_pair(data, uninitialized_copy(b, e, data));
#endif
}inline
#ifdef NOEXCEPT
StrVec::StrVec(StrVec &&s) noexcept  // move won't throw any exceptions
#else
StrVec::StrVec(StrVec &&s) throw()   // move won't throw any exceptions
#endif// member initializers take over the resources in s: elements(s.elements), first_free(s.first_free), cap(s.cap)
{// leave s in a state in which it is safe to run the destructors.elements = s.first_free = s.cap = nullptr;
}inline StrVec::StrVec(const StrVec &s)
{// call alloc_n_copy to allocate exactly as many elements as in sauto newdata = alloc_n_copy(s.begin(), s.end());elements = newdata.first; first_free = cap = newdata.second;
}inline void StrVec::free()
{// may not pass deallocate a 0 pointer; if elements is 0, there's no work to doif (elements) {// destroy the old elements in reverse orderfor (auto p = first_free; p != elements; /* empty */)alloc.destroy(--p);  alloc.deallocate(elements, cap - elements);}
}#ifdef INIT_LIST
inline StrVec &StrVec::operator=(std::initializer_list<std::string> il)
{// alloc_n_copy allocates space and copies elements from the given rangeauto data = alloc_n_copy(il.begin(), il.end());free();   // destroy the elements in this object and free the spaceelements = data.first; // update data members to point to the new spacefirst_free = cap = data.second;return *this;
}
#endif inline
#ifdef NOEXCEPT
StrVec &StrVec::operator=(StrVec &&rhs) noexcept
#else
StrVec &StrVec::operator=(StrVec &&rhs) throw()
#endif
{// direct test for self-assignmentif (this != &rhs) {free();                   // free existing elements elements = rhs.elements;  // take over resources from rhsfirst_free = rhs.first_free;cap = rhs.cap;// leave rhs in a destructible staterhs.elements = rhs.first_free = rhs.cap = nullptr;}return *this;
}inline StrVec &StrVec::operator=(const StrVec &rhs)
{// call alloc_n_copy to allocate exactly as many elements as in rhsauto data = alloc_n_copy(rhs.begin(), rhs.end());free();elements = data.first;first_free = cap = data.second;return *this;
}inline void StrVec::reallocate()
{// we'll allocate space for twice as many elements as the current sizeauto newcapacity = size() ? 2 * size() : 1;// allocate new memoryauto newdata = alloc.allocate(newcapacity);// move the data from the old memory to the newauto dest = newdata;  // points to the next free position in the new arrayauto elem = elements; // points to the next element in the old arrayfor (size_t i = 0; i != size(); ++i)alloc.construct(dest++, std::move(*elem++));free();  // free the old space once we've moved the elements// update our data structure to point to the new elementselements = newdata;first_free = dest;cap = elements + newcapacity;
}#ifdef INIT_LIST
inline StrVec::StrVec(std::initializer_list<std::string> il)
{// call alloc_n_copy to allocate exactly as many elements as in ilauto newdata = alloc_n_copy(il.begin(), il.end());elements = newdata.first;first_free = cap = newdata.second;
}
#else
inline StrVec::StrVec(const std::string *b, const std::string* e)
{// call alloc_n_copy to allocate exactly as many elements as in the rangeauto newdata = alloc_n_copy(b, e);elements = newdata.first;first_free = cap = newdata.second;
}
#endifinline void StrVec::push_back(const std::string& s)
{chk_n_alloc(); // ensure that there is room for another element// construct a copy of s in the element to which first_free pointsalloc.construct(first_free++, s);
}inline void StrVec::push_back(std::string &&s)
{chk_n_alloc(); // reallocates the StrVec if necessaryalloc.construct(first_free++, std::move(s));
}#ifdef VARIADICS    // no direct substitute for variadic functions
// emplace member covered in chapter 16
template <class... Args>
inline void StrVec::emplace_back(Args&&... args)
{chk_n_alloc(); // reallocates the StrVec if necessaryalloc.construct(first_free++, std::forward<Args>(args)...);
}
#endif#endif

【参考】

[1] 代码StrVec.h

C++ Primer 5th笔记(chap 13 拷贝控制) 实例2内存管理相关推荐

  1. C++ Primer 5th笔记(chap 13 拷贝控制)合成的移动操作

    1. 出现条件 只有当一个类没有定义任何自己版本的拷贝控制成员,且类的每个非 static 数据成员都可以移动,编译器才会为它合成构造函数或移动赋值运算符. struc X{int i;std::st ...

  2. C++ Primer 5th笔记(chap 13 拷贝控制)三五法则

    1. 三个基本操作可以控制类的拷贝操作 • 拷贝构造函数 • 拷贝赋值运算符 • 析构函数. 新标准还有2个函数: • 移动构造函数(move constructor) • 移动赋值运算符(move- ...

  3. C++ Primer 5th笔记(chap 13 拷贝控制)阻止拷贝

    对于一些类来说,拷贝操作是没有意义的,例如 iostream 类阻止了拷贝,以避免多个对象写入或读取相同的 IO 缓冲. 1. 删除函数deleted function 1.1 定义 通过在函数的参数 ...

  4. C++ Primer 5th笔记(chap 13 拷贝控制)=default

    可以将拷贝控制成员函数定义为 =default 来显示地要求编译器生成合成版本. class Sales_data{public:Sales_data() = default;Sales_data(c ...

  5. C++ Primer 5th笔记(chap 13 拷贝控制)引用限定符

    1. 问题 关于右值和左值引用成员函数,通常在一个对象上调用成员函数,而不管对象是一个左值还是一个右值: string s1 = "a value",s2 = "anot ...

  6. C++ Primer 5th笔记(chap 13 拷贝控制)实例1

    1. Folder和Message的类设计 2. Messager.h class Message {friend void swap(Message&, Message&);frie ...

  7. C++ Primer 5th笔记(chap 13 拷贝控制) 对象移动

    1. 为什么要有对象移动 使用移动而非拷贝对象能够大大提升性能. 一些不能被共享的资源类的对象不能拷贝但是可以移动.eg. IO 类 unique_ptr 类 2. 如何做到对象移动 2.1 什么是右 ...

  8. C++ Primer 5th笔记(chap 13 拷贝控制)移动构造和移动赋值

    1. 移动构造函数和移动赋值运算符 一般来说,拷贝一个资源会导致一些额外的开销.在这种拷贝并非必要的情况下,定义了移动构造函数和移动赋值运算符的类就可以避免此问题. eg. StrVec::StrVe ...

  9. C++ Primer 5th笔记(chap 13 拷贝控制)交换操作

    1. 类对象的交换赋值 Hasptr.h class Hasptr {public: Hasptr(const std::string &s = std::string()):ps(new s ...

最新文章

  1. 这些Python常用的工具和学习资源你都知道么?
  2. Python学习笔记__13.2章 requests
  3. 尚硅谷最新版JavaWeb全套教程,java web零基础入门完整版(三)
  4. php伪静态url运用,再谈 THINKPHP 伪静态url(URL访问模式)的设置
  5. 工作166:错误的处理方式
  6. LeetCode 386. 字典序排数(DFS循环)
  7. 工欲善其事 必先利其器
  8. java设计模式面试,深入分析
  9. IDEA 日常小技巧
  10. Debugging a Create React App with VS Code
  11. 向日葵远程控制软件linux版安装
  12. 快速入门丨篇八:如何进行运动控制器EtherCAT总线的基础使用?
  13. DLL文件反编译(附:工具下载链接)
  14. springboot开发微信公众号(一)创建、查询、删除菜单(附源码)
  15. 尚硅谷数据结构与算法(Java)--14--插入排序
  16. 东南大学计算机程光,东南大学计算机科学与工程学院硕导介绍:程光
  17. 有两个关系S(A, B, C, D)和T(C, D,E, F), 写出与下列查询等价的SQL表达式:
  18. 计算机硬件综合实验六:CPU组成与机器指令执行实验
  19. matlab 生成 gif
  20. SAP工具箱 数据同步平台(九 与PO整合)

热门文章

  1. Failure while trying to resolve exception [org.springframework.http.converter.HttpMessageNotWritabl
  2. python elseif用法_python学习笔记(一)
  3. r语言 断轴 画图_R 绘图 – 函数曲线图 | 菜鸟教程
  4. 2021年数据中心行业发生了这十件大事
  5. 报告预测:到2027年,全球数据中心基础设施市场规模将达1423.1亿美元
  6. 弱电工程项目综合布线估算方法和公式
  7. 电缆的选择及载流量的计算,超实用~
  8. ajax无刷新留言板远吗,基于jquery实现ajax无刷新评论
  9. 成功解决AttributeError: ‘NoneType‘ object has no attribute ‘shape‘
  10. SLAM:SLAM之VSLAM的简介