0708——学习笔记
using namespace std;
// 实现容器的空间配置器:四个方法(假设创建对象Car)
template <typename T>
struct MyAllocator {
// allocate:申请内存
// deallocate:释放内存
// construct:构造函数
// destory:析构函数
T* allocate(size_t size) {
return (T *)malloc(sizeof(T) * size);
}
//
template<typename... Types>
void construct(T* ptr, Types... args) {
// args只是一个参数,且是Car对象,T也是Car对象
// new (ptr) T(args...); // 所有参数进行展开
new (ptr) T(forward<Types>(args)...); // 增加左右值
}
};
// 定义自己的vector
template<typename T, typename Allo = MyAllocator<T>>
class vector {
public:
// 默认构造
vector():vec_(nullptr), size_(0), idx_(0) {}
// 预留内存空间
void reverse(size_t size) {
// 使用new,不仅会开辟内存,还会构造,交给Allo
vec_ = allocator_.allocate(size);
size_ = size;
}
// push_back
void push_back(const T& val) {
allocator_.construct(vec_ + idx_, val); // 在指针加偏移处,创建一个值为val的对象
idx_++;
}
void push_back(const T&& val) { // 右值引用(右值引用变量)
// 此时val是有名字、有内存,本身是左值
// allocator_.construct(vec_ + idx_, val); // 如果直接传val,是左值,调用左值引用
allocator_.construct(vec_ + idx_, move(val)); // 利用move,进行资源转移
idx_++;
}
// 两个push_back也可以用可变参(此时只有一个参数,也就不用了)+引用折叠
template<typename Type>
void push_back(Type&& val) {
allocator_.construct(vec_ + idx_, forward<Type>(val)); // 利用move就全是右值
idx_++;
}
// 重点:利用可变参模板 + 引用折叠,实现
// emplace 不需要提前创建对象,直接利用参数
template<typename... Types> // ... 代表定义了很多个模板参数
void emplace_back(Types&&... args) {
// ... 可以传多个参数,底层要有适配的函数
// && 引用折叠:假设一个类为Car (根据实参推导出形参是左值引用还是右值引用)
// 传入左值:Car类型推导。Types如果是Car,变成Car&&,变成右值——矛盾
// Car类型推导。Types是Car&,变成Car& &&,引用折叠——Car&
// 传入右值:Car类型推导。Types是Car,变成Car&&,变成右值
// 不管是左值引用变量还是右值引用变量,本身是个左值。
// allocator_.construct(vec_+idx_, args...); // 传递进去全是左值
// 传递过程保持args的引用类型是左/右值 —— 完美转发
allocator_.construct(vec_+idx_, forward<Types>(args)...);
idx_++;
}
private:
T* vec_; // 指向内存
int size_; // 长度
int idx_; // 索引
Allo allocator_; // 构造器
};