C++11新特性
类型推导 auto & decltype
- auto用于推导变量类型
- decltype用于推导表达式类型
右值引用
- 概念
- 左值:可以取地址并且有名字,可以放在等号左边
- 右值:不可以取地址且没有名字,不可以放在等号左边
1 2 3
| int a = b + c; int a = 4;
|
- 左值引用:对左值进行引用
- 右值引用:对右值进行引用
- std::move
将左值强制转换为右值
- std::forward
类型转换,可以转成左值或者右值
- 用途
列表初始化
Example
构造函数初始化列表和构造函数内部赋值
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class CExample { public: int a; float b; CExample(): a(0),b(8.8) {} CExample() { a=0; b=8.8; } };
|
必须使用初始化列表的情况?
成员类型是没有默认构造函数的类。若没有提供显示初始化式,则编译器隐式使用成员类型的默认构造函数,若类没有默认构造函数,则编译器尝试使用默认构造函数将会失败。
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 26 27 28 29 30
| class Person { public: Person(const std::string& name, int age) : name(name), age(age) {}
private: std::string name; int age; };
class Employee { public: Employee(const std::string& name, int age) { person(name, age); }
private: Person person; };
class Employee { public: Employee(const std::string& name, int age) : person(name, age) {}
private: Person person; };
|
智能指针
C++智能指针主要是为了负责自动释放所指向的对象。
Example: 手写Shared_ptr
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| #include <bits/stdc++.h>
template<typename T> class myShared_ptr{ public: explicit myShared_ptr() { _ptr = NULL; _useCnt = new size_t(0); } explicit myShared_ptr(T *p) { _ptr = p; _useCnt = new size_t(1); } myShared_ptr(const myShared_ptr& p) { _ptr = p._ptr; _useCnt = p._useCnt; ++(*_useCnt); } ~myShared_ptr() { --(*_useCnt); if(*_useCnt <= 0) { delete _ptr; delete _useCnt; } } myShared_ptr& operator= (const myShared_ptr& p) { if(_ptr == p._ptr) { return *this; } if(_ptr) { --(*_useCnt); if((*_useCnt) <= 0) { delete _ptr; delete _useCnt; } } _ptr = p._ptr; _useCnt = p._useCnt; ++(*_useCnt); return *this; } void swap(myShared_ptr& p) { std::swap(*this, p); } void getCnt() { std::cout << *_useCnt << std::endl; } private: T* _ptr; size_t* _useCnt; };
int main() { myShared_ptr<int> p1; p1.getCnt(); myShared_ptr<int> p2(new int(1)); p2.getCnt(); myShared_ptr<int> p3(p2); p2.getCnt(); p3.getCnt(); p1 = p3; p1.getCnt(); p3.getCnt(); myShared_ptr<int> p4(new int(1)); p4.swap(p3); p3.getCnt(); p4.getCnt(); return 0; }
|
三种智能指针
- std::shared_ptr:它是一种共享拥有(shared ownership)的智能指针。多个 std::shared_ptr 对象可以共同拥有同一个资源,并且会自动地跟踪资源的引用计数。
- std::unique_ptr:它是一种独占拥有(exclusive ownership)的智能指针。一个 std::unique_ptr 对象拥有资源的独占权,并且不能与其他 std::unique_ptr 或 std::shared_ptr 共享同一个资源。当 std::unique_ptr 对象超出作用域或被显式地释放时,它所拥有的资源会被释放。
- std::weak_ptr:用于解决 std::shared_ptr 的循环引用问题。std::weak_ptr 允许你观测一个资源,而不会增加该资源的引用计数。std::weak_ptr 常用于解决 std::shared_ptr 的循环引用问题。当两个或多个对象相互持有 std::shared_ptr,形成循环引用时,资源可能无法被释放。通过将其中一个或多个 std::shared_ptr 改为 std::weak_ptr,可以打破循环引用,允许资源在不再被引用时被释放。
shared_ptr有哪些安全隐患?
- 引用计数的加减操作是否线程安全?
- 对于引用计数这一变量的存储,是在堆上的,多个shared_ptr的对象都指向同一个堆地址,是线程安全的。
- shared_ptr修改指向时,是否线程安全。
- 多线程代码操作的是同一个shared_ptr的对象时时不安全的。当在多线程中操作同一shared_ptr对象时,数据指针要改指向,sp原先指向的引用计数的值要减去1,other_sp指向的引用计数值要加一。这几步操作加起来并不是一个原子操作。
- 多线程代码操作的不是同一个shared_ptr的对象时,此时发生多线程中修改sp指向的操作时,不会出现非预期的异常行为。但是不代表修改其管理的数据时,不会出现线程安全问题。
C++14新特性
返回值类型推导
1 2 3 4 5 6 7 8
| auto func(int i) { return i; }
int main() { cout << func(4) << endl; return 0; }
|
lambda表达式参数类型推导
1 2
| auto f = [] (int a) { return a; }; auto f = [] (auto a) { return a; };
|
C++17新特性
if-switch语句初始化
1 2 3
| if (int a = GetValue(); a < 101) { cout << a; }
|
内联变量
解决C++类的静态成员变量在头文件中是不能初始化
1 2 3
| struct A { inline static const int value = 10; }
|
namespace嵌套写法优化
1 2 3
| namespace A::B::C { void func(); }
|