委托构造函数
一个委托构造函数使用它所属类的其他构造函数执行它自己的初始化过程,或者说它把它自己的一些(或全部)职责委托给了其他构造函数。
一个委托构造函数也有一个成员初始化值得列表和一个函数体。
在委托构造函数中,成员初始化值列表只有一个唯一得入口,就是类名本身。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class Aet { public: Aet(string s,unsigned cnt,double rusu):name(s),grade(cnt),allresu(rusu) { } //委托构造 Aet():Aet("lif",18,0.0) {} Aet(string s):Aet(s,0,0.0) {} Aet(std::istream & is):Aet() {read(is,*this);} public: string name; unsigned grade; double allresu; }; |
constexpr构造函数
constexpr构造函数用来生成constexpr对象以及constexpr函数的参数或者返回类型。
constexpr构造函数可以声明成=default得形式或者是删除函数得形式。
否则,constexpr构造函数就必须既符合构造函数得要求,又符合constexpr函数的要求(意味着它能拥有的唯一可执行语句就是返回语句)。
结合上述两点:
constexpr构造函数的函数体一般来讲应该是空的。
constexpr构造函数必须初始化所有的数据成员,初始值或者使用constexpr构造函数,或者是一条常量表达式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class Debug { public: constexpr Debug(bool b = true):hw(b),io(b),other(b) {} constexpr Debug(bool h,bool i,bool o):hw(h),io(i),other(o) {} constexpr bool any() {return hw || io || other;} void set_io(bool b) {io = b;} void set_hw(bool h) {hw = h;} void set_other(bool o) {other = o;} private: bool hw; bool io; bool other; }; |
用string类型定义文件名
C++11标准,文件名可以是库类型string对象,也可以是C风格字符串。
旧版本的标准库只允许C风格的字符串。
1 2 3 |
string file; fstream in(file); ostream out; |
array和forward_list容器
- 和内置数组相比,array是一种更安全,更容易使用的数组类型。
- 与内置数组相似,array对象的大小也是固定的。
- forward_list的设计目标是达到与最好的手写的单向链表数据结构相当的性能。(因此,forward_list没有size操作,因为有的话,它需要保存或计算大小,就会比手写链表多出额外的开销)
cbegin和cend
引入cbegin和cend用以支持auto结合begin函数和end函数的使用。
对容器进行列表初始化
1 2 |
list<string> _list = {"aet","lif","wangxu"}; vector<const char *> _char = {"a","b","c"}; |
容器的非成员函数swap
在C++11标准,容器既提供成员函数版本的swap,也提供非成员函版本的swap函数。
(非成员版本的swap在泛型编程中是比较重要的,统一使用非成员版本的swap是一个好习惯。)
容器insert成员的返回类型
C++11标准,接受元素个数或范围的insert版本,返回指向第一个新加入的元素的迭代器。
(旧版本,这些操作返回void)
如果,范围为空,不插入任何元素,insert操作将会将第一个参数返回。
容器的emplace成员
C++11标准,新引入了三个成员
- emplace_front---将元素放置在容器头部
- emplace---将元素放置在指定位置之前
- emplace_back---将元素放置在容器尾部
这些操作,是构造元素,而不是拷贝元素。
分部对应: - push_front
- insert
- push_back
shrink_to_fit
在C++11标准中,我们可以使用shrink_to_fit来要求deque,vector和string退回不需要的内存空间。
此函数指出我们不再需要多余的内存空间
但是,具体的实现可以选择忽略这样的请求,也就是说,调用shrink_to_fit并不保证一定退回内存空间。
string的数值转换
C++11标准引入了多个函数,可以实现数值数据与标准库string之间的转换。
1 2 3 4 5 6 7 8 9 10 11 |
//转成string to_string() // stoi(s,p,b) stol(s,p,b) stoul(s,p,b) stoll(s,p,b) stoull(s,p,b) stof(s,p) stod(s,p) stold(s,p) |
1 2 3 4 5 6 |
int i = 32; string s = to_string(i); double d = stod(s); string test = "pi = 3.14"; d = stod(test.substr(test.find_first_of("+-.0123456789")));//d = 3.14 |
lambda表达式
我们可以向一个算法传递任何类别的可调用对象。
一个lambda表达式表示一个可调用的代码单元。
可以将其理解为一个未命名的内联函数
与任何函数类似,一个lambda表达式具有也一个返回类型,一个参数列表和一个函数体。
和函数不同的是,lambda表达式可以定义在函数内部。
其格式如下:
[捕获列表](参数列表)->返回类型 {函数体}
注意:
我们可以忽略参数列表和返回类型,但永远得包含捕获列表和函数体。
1 2 |
auto f = [] {return 32;}; cout << f() << endl;//32 |
1 2 3 4 5 |
//带参数得lambda [](const string & lhs,const string & rhs) {return lhs.size() < rhs.size();}; //使用捕获列表得lambda [_size](const string & str) {return str.size() >= _size;}; |
关于捕获列表:
[] | 空捕获列表,lambda不能使用所在函数中的变量 |
[names] | names是一个逗号分隔的名字列表,这些名字都是lambda所在函数的局部变量。 |
[&] | 隐式捕获列表,采用引用捕获的方式。lambda中所使用的和来自所占函数的实体都采用引用的方式使用 |
[=] | 隐式捕获列表,采用值捕获方式。lambda体将拷贝所使用的来自所在函数的实体的值 |
[&,identifier_list] | identifier_list是也给逗号分隔的列表,包含0个或多个所占函数的变量。这些变量采用值捕获的方式,而任何隐式捕获的变量都采用引用捕获的方式捕获。identifier_list的名字前不能使用&。 |
[=,identifier_list] | identifier_list中的变量都采用引用捕获的方式。而任何隐式捕获的变量都采用值捕获的方式捕获。identifier_list中的名字不能包括this,且这些名字之前必须使用&。 |
另外:
当我们需要为一个lambda定义返回类型的时候,必须使用尾置返回类型。
1 |
transform(vi.begin(),vi.end(),vi.begin(),[](int i)->int{if(i < 0) return -i;else return i;}); |
标准库bind函数
定义在functional中
可以将bind看作一个同样的函数适配器:它接受一个可调用对象,来生成一个新的可调用对象来“适应”原来对象的参数列表。
格式:
auto newCallable = bind(callable,arg_list);
arg_list中,可能包含_n的名字,n是一个整数,这些参数是占位符,表示它是newCallbale的参数,它们占据了传递给newCallable的参数的位置。
1 2 3 4 5 6 7 8 9 |
//函数 bool check_size(const string & lhs,string::size_type sz) { return lhs.size() >= sz; } //_1表示newcheck接受一个string类型的参数,并用这个string和6去调用check_size auto newcheck = bind(check_szie,_1,6); string str = "hello"; bool _result = newcheck(str); |
关联容器的列表初始化
1 2 |
set<string> _set = {"a","b","c"}; map<string,string> _map = { {"a","b"},{"c","d"},{"e","f"}}; |
pair
pair<T1,T2> p; | 两个类型为T1,T2的成员都进行了值初始化 |
pair<T1,T2> p(v1,v2) | first和second分部用v1,v2初始化 |
pair<T1,T2> p = {v1,v2} | |
make_pair(v1,v2) | 利用v1和v2初始化pair,类型会推导出来 |
在C++11标准下,我们是可以对返回值进行列表初始化的
1 2 3 4 5 6 7 |
pair<string,int> process(vector<string> & v) { if(!v.empty()) return {v.back(),v.back().size()};//列表初始化 else return pair<string,int>();//隐式构造返回值 } |
无序容器
C++11标准定义了4个无序容器
这些容器不是用比较运算符来组织元素,而是使用一个哈希函数和关键字类型的==运算符。
在关键字类型的元素没有明显的序关系的情况下,无序容器是非常有用的。
unordered_map | 保存关键字-值对的关系,不允许出现重复关键字 |
unordered_multimap | 保存关键字-值对的关系,允许出现重复关键字 |
unordered_set | 保存关键字的容器,不允许出现重复关键字 |
unordered_multiset | 保存关键字的容器,允许出现重复关键字 |
管理桶
无序容器在存储上组织为一组桶,每个桶保存0个或多个元素。
无序容器使用一个哈希函数将元素映射到桶。
为了访问一个元素,容器首先计算元素的哈希值,这个哈希值指出应该搜索哪个桶。(容器会将具有一个指定哈希值的所有元素都保存在相同的桶中。)
如果容器允许出现重复的关键字,那么所有具有相同关键字的元素也都会出现在同一个桶中。
因此,无序容器的性能依赖于哈希函数的质量,以及桶的数量和大小。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
//桶接口// //正在使用的桶的数量 c.bucket_count() //容器能容纳的最多的桶的数量 c.max_bucket_count() //第n个桶中有多少个元素 c.bucket_size(n) //关键字为k的元素在哪个桶中 c.bucket(k) //桶迭代// local_iterator//可以用来访问桶中元素的迭代器类型 const_local_iterator//const版本 c.begin(n),c.end(n)//桶n的首元素迭代器和尾后迭代器 c.cbegin(n),c.cend(n)//const //桶策略// //每个桶的平均元素数量,float c.load_factor() //c试图维护的平均桶大小,float c.max_load_factor() //重组存储 c.rehash(n) //重组存储 c.reserve(n) |
智能指针
在memory头文件中
C++11标准提供了两种智能指针类型来管理动态对象
这这种智能指针的区别:
shared_ptr允许多个指针指向同一个对象
unique_ptr则独占所指向的对象
标准库里还有个weak_ptr,它是一种弱引用,指向shared_ptr所管理的对象
shared_ptr独有的操作:
make_shared |
返回一个shared_ptr,指向一个动态分配的类型为T的对象,使用args初始化 |
shared_ptr |
p是shared_ptr的拷贝,此操作会递增q中计数器 |
p = q | 此操作会递减p的引用计数,递增q的引用计数,若p的引用计数为0,则会将其管理的原内存释放 |
p.unique() | 若p.use_count()为1,返回true,否则返回false |
p.use_count() | 返回与p共享对象的智能指针数量(可能很慢,主要用于调试) |
1 2 3 4 5 6 |
//指向一个值为int的智能指针 shared_ptr<int> _p = make_shared<int>(40); //指向9999999999的string shared_ptr<string> _ps = make_shared<string>(10,'9'); //指向一个初始化为0的int shared_ptr<int> _pi = make_shared<int>(); |
本文为原创文章,版权归Aet所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ C++并发编程 _ 同步并发(Future)05/22
- ♥ C++_指针引用09/19
- ♥ Spdlog记述:四09/16
- ♥ STL_了解05/02
- ♥ Objective-C 解析plist04/28
- ♥ C++_关于对象的具体初始化顺序11/30