可变参表示参数的类型和数量都可变
void show(int a, string b) {
cout << a << endl;
cout << b << endl;
}
template<typename... Types>
void fun(Types... args) {
show(args...);
}
int main() {
fun(1, "hello");
return 0;
}
使用空间配置器和可变参模板的vector
#include
#include
#include
using namespace std;
const int INIT_SIZE = 10;
class Test{
public:
Test(int a)
: a_(a)
, b_("")
{
cout << "Test(int)" << endl;
}
Test(int a, string b)
: a_(a)
, b_(b)
{
cout << "Test(int,string)" << endl;
}
Test(const Test& a) { cout << "Test(const Test&)" << endl; }
Test(const Test&& a) { cout << "Test(const Test&&)" << endl; }
~Test() { cout << "~Test()" << endl; }
int a_;
string b_;
};
template<typename T>
class Allocator {
public:
// 开辟size字节
T* allocate(size_t size) {
return (T*)malloc(size);
}
void deallocate(void* p) {
free(p);
}
template<typename... Types>
void construct(T* p, Types&&... args) {
// 当给emplace传入Test对象时,Types就是Test&或Test&&,T就是Test
// 当给emplace传入Test构造所需参数时,Types就是int string,可变参表示参数的类型和数量都可变
new (p) T(std::forward<Types>(args)...);
}
void destroy(T* p) {
p->~T();
}
};
template<typename T, typename Alloc = Allocator<T>>
class Vector {
public:
Vector(int size = INIT_SIZE, const Alloc& alloc = Allocator<T>())
: allocator_(alloc)
{
// first_ = new T[size];
first_ = allocator_.allocate(size * sizeof(T));
last_ = first_;
end_ = first_ + size;
}
~Vector() {
// delete[] first_;
// 析构时,只析构容器中有效元素[first_, last - 1]
for (T* p = first_; p != last_; p++) {
allocator_.destroy(p);
}
// 释放整个容器空间
allocator_.deallocate(first_);
last_ = first_ = end_ = nullptr;
}
Vector(const Vector<T>& src) {
// 深拷贝
// 开辟空间
int size = src.end_ - src.first_;
// first_ = new T[size];
first_ = allocator_.allocate(sizeof(T) * size);
// 拷贝有效元素
int len = src.last_ - src.first_;
for (int i = 0; i < len; i++) {
// first_[i] = src.first_[i];
allocator_.construct(first_ + i, src.first_[i]);
}
last_ = first_ + len;
end_ = first_ + size;
}
Vector<T>& operator=(const Vector<T>& src) {
if (this == &src) {
return *this;
}
// 释放当前对象原来的资源
// delete[] first_;
for (T* p = first_; p != last_; p++) {
allocator_.destroy(p);
}
allocator_.deallocate(first_);
last_ = first_ = end_ = nullptr;
// 开辟空间
int size = src.end_ - src.first_;
// first_ = new T[size];
first_ = allocator_.allocate(sizeof(T) * size);
// 拷贝有效元素
int len = src.last_ - src.first_;
for (int i = 0; i < len; i++) {
allocator_.construct(first_ + i, src.first_[i]);
}
last_ = first_ + len;
end_ = first_ + size;
// 支持连续赋值
return *this;
}
bool inline full() const {
return last_ == end_;
}
bool inline empty() const {
return first_ == last_;
}
bool inline size() const {
return last_ - first_;
}
// 在容器末尾构造一个值为val的对象
// 会发生引用折叠,参数是左值,则Types是Test&,引用折叠后,val是Test&
// 参数是右值,则Types是Test&&,引用折叠后,val是Test&&
template<typename Types>
void push_back(Types&& val) {
if (full()) {
expand();
}
allocator_.construct(last_, std::forward<Types>(val));
last_++;
}
// 从末尾删除元素
void pop_back() {
if (empty()) {
return;
}
last_--;
allocator_.destroy(last_);
}
T back() const {
return *(last_ - 1);
}
template<typename... Types>
void emplace_back(Types&&... args) {
if (full()) {
expand();
}
// 不管是左值引用变量还是右值引用变量,都是左值,需要用forward保持左值或右值的特性传递到空间配置器,再传递到元素的构造函数
allocator_.construct(last_, std::forward<Types>(args)...);
last_++;
}
void reserve(size_t n) {
allocator_.allocate(sizeof(T) * n);
end_ += n;
}
private:
void expand() {
int size = end_ - first_;
// T* tmp = new T [2 * size];
T* tmp = allocator_.allocate(2 * sizeof(T) * size);
for (int i = 0; i < size; i++) {
allocator_.construct(tmp + i, first_[i]);
}
// delete[] first_;
for (T* p = first_; p != last_; p++) {
allocator_.destroy(p);
}
allocator_.deallocate(first_);
first_ = tmp;
last_ = first_ + size;
end_ = first_ + 2 * size;
}
T* first_; // 指向数组起始位置
T* last_; // 指向数组中有效元素的后继位置
T* end_; // 指向数组空间的后继位置
Alloc allocator_;
};
int main(){
Vector<Test> v;
v.reserve(100);
v.push_back(Test(10, "hello")); // 右值拷贝构造,引用方式传递,临时对象析构后,容器底层的对象数据也不对
cout << "=====================" << endl;
v.emplace_back(11, "world");
cout << "=====================" << endl;
return 0;
}
空间配置器Allocator
template<typename T>
class Allocator {
public:
// 开辟size字节
T* allocate(size_t size) {
return (T*)malloc(size);
}
void deallocate(void* p) {
free(p);
}
template<typename... Types>
void construct(T* p, Types&&... args) {
// T就是Test
// 当给emplace传入Test对象时,Types就是Test&或Test&&
// 当给emplace传入Test构造所需参数时,Types就是int string,可变参表示参数的类型和数量都可变
new (p) T(std::forward<Types>(args)...);
}
void destroy(T* p) {
p->~T();
}
};
基于可变参模板和引用折叠的emplace_back
template<typename... Types>
void emplace_back(Types&&... args) {
if (full()) {
expand();
}
// 不管是左值引用变量还是右值引用变量,都是左值,需要用forward
allocator_.construct(last_, std::forward<Types>(args)...);
last_++;
}
如果给emplace_back传入的左值,则Types是Test&,引用折叠后args就是Test&
如果给emplace_back传入的右值,则Types是Test&&,引用折叠后args就是Test&&