练习13.45:
所谓右值引用就是必须绑定到右值的引用,通过&&而不是&来获得右值引用,右值引用只能绑定到一个将要销毁的对象上,我们可以自由地将一个右值引用的资源“移动”到另一个对象中
一个左值表达式表达的是一个对象的身份,而一个右值表达式表示的是对象的值
左值持久,右值短暂
练习13.46:
r1是右值(返回非引用):int&& r1
r2是左值(下标):int& r2
r3是左值(变量引用):int& r3
r4是右值(算术运算):int&& r4
练习13.47:
//拷贝构造函数
String::String(const String& cv)
{
//调用alloc_n_copy分配空间以容纳与sv中一样多的元素
auto newData = alloc_n_copy(cv.begin(), cv.end());
elements = newData.first;
first_free = cap = newData.second;
cout << "copy construct function" << endl;
}
//拷贝赋值运算符
String& String::operator=(const String& cv)
{
//为了正确处理自赋值,在释放已有元素前调用alloc_n_copy
//分配内存,大小和sv中占用的元素一样多
auto data = alloc_n_copy(cv.begin(), cv.end());
free();
elements = data.first;
first_free = cap = data.second;
cout << "copy assignment operator" << endl;
return *this;
}
练习13.48:
#include <iostream>
#include <string>
using namespace std;
#include <algorithm>
#include <fstream>
#include <memory>
#include <set>
#include <map>
#include <sstream>
#include <vector>
//标准库string的简化实现
class String{
public:
//默认初始化
String();
//接受C风格字符串指针参数
String(const char*);
//接受初始值列表的构造函数
String(initializer_list<char>);
//拷贝构造函数
String(const String&);
//拷贝赋值运算符
String& operator=(const String&);
//析构函数
~String();
//添加元素
void push_back(const char&);
//数组大小和容量
size_t size()const;
size_t capacity()const;
//获得数组的首元素和尾后元素
char* begin()const;
char* end()const;
void reserve(size_t n);
void resize(size_t n);
private:
//静态成员,用来分配元素,工具人,不需要每个对象都分配,设置为静态成员
static std::allocator<char>alloc;
//工具函数,被添加元素的函数所使用
void chk_n_alloc();
//工具函数,被拷贝构造函数、赋值运算符和析构函数使用
std::pair<char*, char*>alloc_n_copy(const char*, const char*);
void free();
//获得更多内存并拷贝已有元素
void reallocate();
//指向数组首元素的指针
char* elements;
//指向数组第一个空闲元素的指针
char* first_free;
//指向数组尾后位置的指针
char* cap;
};
//静态成员变量需要在类外定义,但不一定要初始化
std::allocator<char> String::alloc;
//reallocate成员
void String::reallocate()
{
//分配当前大小两倍的内存空间
auto newCapacity = size() ? 2 * size() : 1;
//分配新内存
auto newData = alloc.allocate(newCapacity);
//将数据从旧内存移到新内存
//指向数组下一个空闲位置
auto dest = newData;
//指向旧数组中下一个元素
auto elem = elements;
for (size_t i = 0; i != size(); ++i)
{
alloc.construct(dest++, std::move(*elem++));
}
//一旦我们移动完元素就释放旧内存空间
free();
//更新我们的数据结构,执行新元素
elements = newData;
first_free = dest;
cap = elements + newCapacity;
}
size_t String::capacity()const
{
return cap - elements;
}
void String::chk_n_alloc()
{
if (size() == capacity())
{
reallocate();
}
}
size_t String::size()const
{
return first_free - elements;
}
char* String::begin()const
{
return elements;
}
char* String::end()const
{
return first_free;
}
//push_back
void String::push_back(const char& c)
{
chk_n_alloc();
//此时有足够的空间,创建元素,拷贝
alloc.construct(first_free++, c);
}
//工具函数,被拷贝构造函数、赋值运算符和析构函数使用
pair<char*, char*> String::alloc_n_copy(const char* c1, const char* c2)
{
//拷贝传递参数指定范围的元素
//创建元素的副本
auto data = alloc.allocate(c2 - c1);
//uninitialized_copy(b,e,b2)作用是从迭代器b和e指出的输出范围中拷贝元素到迭代器b2指定的未构造的原始内存中
// 使用uninitialized_copy(b,e,b2)函数对未构造的函数进行拷贝
//返回一个pair,分别指向拷贝后的数组首元素和最后元素后面的元素
return { data,uninitialized_copy(c1,c2,data) };
}
//free
void String::free()
{
//不能传递给deallocate一个空指针,如果elements为空,函数就什么也不做
if (elements)
{
for_each(elements, first_free, [](char& p) {alloc.destroy(&p); });
alloc.deallocate(elements, cap - elements);
}
}
//默认初始化
String::String() :elements(nullptr), first_free(nullptr), cap(nullptr)
{
}
//接受C风格字符串指针参数
String::String(const char* str)
{
//确定数组大小
auto newCapacity = strlen(str);
//创建内存
auto newData = alloc.allocate(newCapacity);
elements = newData;
//复制元素
auto p = uninitialized_copy(str, str + newCapacity, newData);
//更新指针
first_free = p;
cap = elements + newCapacity;
}
//拷贝构造函数
String::String(const String& cv)
{
//调用alloc_n_copy分配空间以容纳与sv中一样多的元素
auto newData = alloc_n_copy(cv.begin(), cv.end());
elements = newData.first;
first_free = cap = newData.second;
cout << "copy construct function" << endl;
}
//拷贝赋值运算符
String& String::operator=(const String& cv)
{
//为了正确处理自赋值,在释放已有元素前调用alloc_n_copy
//分配内存,大小和sv中占用的元素一样多
auto data = alloc_n_copy(cv.begin(), cv.end());
free();
elements = data.first;
first_free = cap = data.second;
cout << "copy assignment operator" << endl;
return *this;
}
//接受初始值列表的构造函数
String::String(initializer_list<char>l)
{
//使用alloc_n_copy赋值元素,创建内存
auto newData = alloc_n_copy(l.begin(), l.end());
elements = newData.first;
first_free = newData.second;
}
//析构函数
String::~String()
{
free();
}
void String::reserve(size_t n)
{
//分配大小为n的内存
if (capacity() < n)
{
auto newCapacity = n;
//创建新内存
auto newData = alloc.allocate(n);
//将数据从旧内存移到新内存
//指向数组下一个空闲位置
auto dest = newData;
//指向旧数组中下一个元素
auto elem = elements;
//将数据移动
for (size_t i = 0; i != size(); ++i)
{
alloc.construct(dest++, std::move(*elem));
}
//一旦我们移动完元素就释放旧内存空间
free();
//更新我们的数据结构,执行新元素
elements = newData;
first_free = dest;
cap = elements + newCapacity;
}
}
void String::resize(size_t n)
{
//n的大小大于size(),以默认值填充
if (size() < n)
{
size_t num = n - size();
for (size_t i = 0; i != num; ++i)
{
alloc.construct(first_free++, char());
}
}
//n的大小小于size(),删除
if (size() > n)
{
//从n开始destory内存
for (auto p = elements + n; p != first_free; ++p)
{
alloc.destroy(p);
}
//更新first_free
first_free = elements + n;
}
}
int main()
{
//测试
String s1("hello ");
String s2("world!!!");
String s3("C++");
vector<String>vs;
vs.push_back(s1);
vs.push_back(s2);
s3 = s2;
system("pause");
return 0;
}
结果: