建设包包网站的目的,公众号与网站,刚做的网站怎么搜索不出来的,超级采购小程序怎么注册C新增的类功能和可变参数模板 新的类功能默认成员函数 可变参数模板模拟实现emplace_back #x1f30f;个人博客主页#xff1a;
个人主页 新的类功能
默认成员函数
原来C类中#xff0c;有6个默认成员函数#xff1a;
构造函数析构函数拷贝构造函数拷贝赋值重载取地址… C新增的类功能和可变参数模板 新的类功能默认成员函数 可变参数模板模拟实现emplace_back 个人博客主页
个人主页 新的类功能
默认成员函数
原来C类中有6个默认成员函数
构造函数析构函数拷贝构造函数拷贝赋值重载取地址重载const 取地址重载 最后重要的是前4个后两个用处不大。默认成员函数就是我们不写编译器会生成一个默认的。C11 新增了两个移动构造函数和移动赋值运算符重载。
为了方便观察我们写一个简单的string
class string
{public:typedef char* iterator;iterator begin(){return _str;}iterator end(){return _str _size;}typedef const char* const_iterator;const_iterator begin() const{return _str;}const_iterator end() const{return _str _size;}string(const char* str ):_size(strlen(str)), _capacity(_size){cout string(char* str) endl;_str new char[_capacity 1];strcpy(_str, str);}// s1.swap(s2)void swap(string s){::swap(_str, s._str);::swap(_size, s._size);::swap(_capacity, s._capacity);}// 拷贝构造// s2(s1)string(const string s):_str(nullptr){cout string(const string s) -- 深拷贝 endl;reserve(s._capacity);for (auto ch : s){push_back(ch);}}// 移动构造// 临时创建的对象不能取地址用完就要消亡// 深拷贝的类移动构造才有意义string(string s):_str(nullptr){cout string(string s) -- 移动拷贝 endl;swap(s);}// 赋值重载string operator(const string s){cout string operator(const string s) -- 深拷贝 endl;if (this ! s){_str[0] \0;_size 0;reserve(s._capacity);for (auto ch : s){push_back(ch);}}return *this;}// 移动赋值string operator(string s){cout string operator(string s) -- 移动赋值 endl;swap(s);return *this;}~string(){cout ~string() endl;delete[] _str;_str nullptr;}char operator[](size_t pos){assert(pos _size);return _str[pos];}void reserve(size_t n){if (n _capacity){char* tmp new char[n 1];if (_str){strcpy(tmp, _str);delete[] _str;}_str tmp;_capacity n;}}void push_back(char ch){if (_size _capacity){size_t newcapacity _capacity 0 ? 4 : _capacity * 2;reserve(newcapacity);}_str[_size] ch;_size;_str[_size] \0;}//string operator(char ch)string operator(char ch){push_back(ch);return *this;}const char* c_str() const{return _str;}private:char* _str nullptr;size_t _size 0;size_t _capacity 0; // 不包含最后做标识的\0};
}针对移动构造函数和移动赋值运算符重载有一些需要注意的点如下
如果你没有自己实现移动构造函数且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任意一个。那么编译器会自动生成一个默认移动构造。默认生成的移动构造函数对于内置类型成员会执行逐成员按字节拷贝自定义类型成员则需要看这个成员是否实现移动构造如果实现了就调用移动构造没有实现就调用拷贝构造。
class Person
{
public:Person(const char* name , int age 0):_name(name),_age(age){}
private:string _name;int _age;
};int main()
{Person s1(Peter,18);Person s2 s1;Person s3 move(s1);return 0;
}为什么这里的条件怎么苛刻呢?
因为如果一个类需要显示写析构说明有资源需要释放那么通常就要写析构函数拷贝构造拷贝赋值运算重载对资源进行管理假如一个类是由自定义类型和内置类型构成的对于内置类型不需要进行资源管理只要完成值拷贝就可以了而且要不用释放资源对于自定义类型如果由资源需要管理我们只需要调用它对应写的函数即可这样就不用我们单独写了例如Person类。
所以这里的条件是合理的。
如果你没有自己实现移动赋值重载函数且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任意一个那么编译器会自动生成一个默认移动赋值。
默认生成的移动构造函数对于内置类型成员会执行逐成员按字节拷贝自定义类型成员则需要看这个成员是否实现移动赋值如果实现了就调用移动赋值没有实现就调用拷贝赋值。(默认移动赋值跟上面移动构造完全类似)如果你提供了移动构造或者移动赋值编译器不会自动提供拷贝构造和拷贝赋值。
class Person
{
public:Person(const char* name , int age 0):_name(name),_age(age){}
private:string _name;int _age;
};int main()
{Person s1(Peter,18);Person s2;s2 s1;Person s3;s3 move(s1);return 0;
}如果你提供了移动构造或者移动赋值编译器不会自动提供拷贝构造和拷贝赋值。 class Person
{
public:Person(const char* name , int age 0):_name(name),_age(age){}Person(Person s) default;
private:string _name;int _age;
};int main()
{Person s1(Peter,18);Person s2 s1;//errreturn 0;
}因为如果我们不写拷贝构造编译器就会生成默认的拷贝构造对于内置类型完成值拷贝对应自定义类型对调用其对应的拷贝构造但是如果我们显示写了移动构造编译器会把移动构造当做拷贝构造的一种就不会生成默认的拷贝构造只能完成右值对应的拷贝。
强制生成默认函数的关键字default
C11可以让你更好的控制要使用的默认函数。假设你要使用某个默认的函数但是因为一些原因这个函数没有默认生成。比如我们提供了拷贝构造就不会生成移动构造了那么我们可以使用default关键字显示指定移动构造生成。
class Person
{
public:Person(const char* name , int age 0):_name(name), _age(age){}Person(const Person p):_name(p._name),_age(p._age){}Person(Person p) default;
private:string _name;int _age;
};禁止生成默认函数的关键字delete:
如果能想要限制某些默认函数的生成在C98中是该函数设置成private并且只声明补丁已这样只要其他人想要调用就会报错。在C11中更简单只需在该函数声明加上delete即可该语法指示编译器不生成对应函数的默认版本称delete修饰的函数为删除函数。
class Person
{
public:Person(const char* name , int age 0):_name(name),_age(age){}//Person(const Person s) delete;Person(Person s) delete;
private:string _name;int _age;
};我们只需要禁用拷贝构造或者移动构造中的一个另一个就不会自动生成赋值重载也是同样的道理。 可变参数模板
C11的新特性可变参数模板能够让您创建可以接受可变参数的函数模板和类模板。
下面就是一个基本可变参数的函数模板
// Args是一个模板参数包args是一个函数形参参数包
// 声明一个参数包Args...args这个参数包中可以包含0到任意个模板参数。
template class ...Args
void ShowList(Args... args)
{cout sizeof...(args) endl;
}int main()
{ShowList();ShowList(x);ShowList(x, y);
}上面的参数args前面有省略号所以它就是一个可变模版参数我们把带省略号的参数称为“参数包”它里面包含了0到NN0个模版参数。我们无法直接获取参数包args中的每个参数的只能通过展开参数包的方式来获取参数包中的每个参数。
递归函数方式展开参数包
void ShowList()
{cout endl;
}template class T, class ...Args
void ShowList(const T val, Args... args)
{cout val ;ShowList(args...);
}int main()
{ShowList();ShowList(x);ShowList(x, y);ShowList(1,x, y);
}逗号表达式展开参数包
template class T
void PrintArg(T t)
{cout t ;
}template class ...Args
void ShowList(Args... args)
{int arr[] { (PrintArg(args),0)... };cout endl;
}int main()
{ShowList(x);ShowList(x, y);ShowList(1,x, y);
}也可以这样写
template class T
int PrintArg(T t)
{cout t ;return 0;
}template class ...Args
void ShowList(Args... args)
{int arr[] { PrintArg(args)... };cout endl;
}int main()
{ShowList(x);ShowList(x, y);ShowList(1,x, y);
}实际编译器编译推演生成了一下代码
template class T
int PrintArg(T t)
{cout t ;return 0;
}void ShowList(int a,char b,char c)
{int arr[] { PrintArg(a),PrintArg(b),PrintArg(c)};cout endl;
}int main()
{ShowList(1,x, y);
}STL容器中的empalce相关接口函数 template class ...Args
void emplace_back(Args ...args)
{//...
}首先我们看到的emplace系列的接口支持模板的可变参数并且万能引用。那么emplace系列接口的优势到底在哪里呢
int main()
{listbit::string mylist;//没有区别string s1(1111);mylist.push_back(s1);mylist.emplace_back(s1);cout endl;string s2(2222);mylist.push_back(move(s1));mylist.emplace_back(move(s2));//有区别cout endl;//先构造临时对象 移动构造mylist.push_back(1111);//直接构造mylist.emplace_back(1111);
}模拟实现emplace_back
#pragma once
#include assert.h#include iostreamusing namespace std;namespace hb
{template class Tstruct ListNode{ListNodeT* _prev;ListNodeT* _next;T _data;ListNode(const T data T()):_prev(nullptr), _next(nullptr), _data(data){}ListNode(T data):_prev(nullptr), _next(nullptr), _data(move(data)){}template class ...ArgsListNode(Args... args): _prev(nullptr), _next(nullptr), _data(forwardArgs(args)...){}};template class T,class Ref,class Ptrstruct ListIterator{typedef ListNodeT Node;Node* _node;typedef ListIteratorT,Ref,Ptr self;ListIterator(Node* node):_node(node){}self operator(){_node _node-_next;return *this;}self operator(int){self tmp(*this);_node _node-_next;return tmp;}self operator--(){_node _node-_prev;return *this;}self operator--(int){self tmp(*this);_node _node-_prev;return tmp;}Ref operator*(){return _node-_data;}bool operator!(const self node){return _node ! node._node;}bool operator(const self node){return _node node._node;}Ptr operator-(){return _node-_data;}};template class Tstruct ListConstIterator{typedef ListNodeT Node;Node* _node;typedef ListConstIteratorT self;ListConstIterator(Node* node):_node(node){}self operator(){_node _node-_next;return *this;}self operator(int){self tmp(*this);_node _node-_next;return tmp;}self operator--(){_node _node-_prev;return *this;}self operator--(int){self tmp(*this);_node _node-_prev;return tmp;}const T operator*(){return _node-_data;}bool operator!(const self node){return _node ! node._node;}bool operator(const self node){return _node node._node;}const T* operator-(){return _node-_data;}};template class Tclass list{typedef ListNodeT Node;public:typedef ListIteratorT,T,T* iterator;typedef ListIteratorT,const T,const T* const_iterator;//typedef ListConstIteratorT const_iterator;iterator begin(){return iterator(_head-_next);}const_iterator begin() const{return const_iterator(_head-_next);}iterator end(){return iterator(_head);}const_iterator end() const{return const_iterator(_head);}void empty_list(){_head new Node;_head-_prev _head;_head-_next _head;}list(){empty_list();}~list(){clear();delete _head;_head nullptr;}void clear(){iterator it begin();while (it ! end()){//it erase(it);erase(it);}}/*list(const listT lt){empty_list();for (const auto e : lt){push_back(e);}}*/void swap(listT tmp){std::swap(_head, tmp._head);}template class Iteratorlist(Iterator first, Iterator last){empty_list();//不加会出问题while (first ! last){push_back(*first);first;}}list(const listT lt){empty_list();listT tmp(lt.begin(), lt.end());swap(tmp);}listT operator(listT tmp){swap(tmp);return *this;}void push_back(const T x){/*Node* tail _head-_prev;Node* newnode new Node(x);newnode-_prev tail;newnode-_next _head;tail-_next newnode;_head-_prev newnode;*/insert(end(),x);}void push_back(T x){/*Node* tail _head-_prev;Node* newnode new Node(x);newnode-_prev tail;newnode-_next _head;tail-_next newnode;_head-_prev newnode;*/insert(end(), move(x));}template class ...Argsvoid emplace_back(Args ...args){insert(end(), forwardArgs(args)...);}void push_front(const T x){insert(begin(),x);}void pop_back(){erase(--end());}void pop_front(){erase(begin());}iterator insert(iterator pos, const T x){Node* node pos._node;Node* prev node-_prev;Node* newnode new Node(x);newnode-_prev prev;newnode-_next node;prev-_next newnode;node-_prev newnode;return iterator(newnode);}templateclass ...Argsiterator insert(iterator pos, Args... args){Node* node pos._node;Node* prev node-_prev;Node* newnode new Node(forwardArgs(args)...);newnode-_prev prev;newnode-_next node;prev-_next newnode;node-_prev newnode;return iterator(newnode);}iterator insert(iterator pos, T x){Node* node pos._node;Node* prev node-_prev;Node* newnode new Node(move(x));newnode-_prev prev;newnode-_next node;prev-_next newnode;node-_prev newnode;return iterator(newnode);}iterator erase(iterator pos){assert(pos ! end());Node* del pos._node;Node* prev del-_prev;Node* next del-_next;prev-_next next;next-_prev prev;return iterator(next);}bool empty() const{return _head _head-_next;}T front(){return _head-_next-_data;}const T front() const{return _head-_next-_data;}T back(){return _head-_prev-_data;}const T back() const{return _head-_prev-_data;}size_t size() const{size_t count 0;Node* pcur _head-_next;while (pcur ! _head){count;pcur pcur-_next;}return count;}void resize(size_t newsize, const T data T()){size_t oldsize size();if (newsize oldsize){while (newsize ! oldsize){pop_back();oldsize--;}}else{while (oldsize ! newsize){push_back(data);oldsize;}}}private:Node* _head;};
}代码测试
int main()
{hb::liststring mylist;//没有区别string s1(1111);mylist.push_back(s1);mylist.emplace_back(s1);cout endl;string s2(2222);mylist.push_back(move(s1));mylist.emplace_back(move(s2));//有区别cout endl;//先构造临时对象 移动构造mylist.push_back(1111);//直接构造mylist.emplace_back(1111);
}