XuQi's Blog

  • 首页

  • 归档

C++常用新特性

发表于 2019-06-05 更新于 2019-10-20

C++11 & C++14 & C++17 常用新特性总结

GCC编译器(从编译器GCC4.8.X的版本完全支持)

  (1)目前C++11特性,之前成为C++0X特性,从GCC4.3的后续版本中逐步对C++11进行支持。

  (2)从官方信息可以看到,目前从完全对C++11特性进行支持的是从编译器GCC4.8.X的版本。

  参考网址:https://gcc.gnu.org/projects/cxx-status.html#cxx11

​ 编译的时候加上参数:

1
-std=c++11

C+11新特性

nullptr

传统 C++ 会把 NULL、0 视为同一种东西,这取决于编译器如何定义NULL,有些编译器会将 NULL 定义为 ((void*)0),有些则会直接将其定义为 0.

C++ 不允许直接将 void * 隐式转换到其他类型,但如果 NULL 被定义为 ((void*)0),那么当编译char *ch = NULL;时,NULL 只好被定义为 0。

这样就会导致重载特性混乱,比如foo(NULL)调用的是foo(int)

1
2
void foo(char *);
void foo(int);

类型推导 auto和decltype

auto

常见用法:

1
2
3
4
5
for(vector<int>::const_iterator it = vec.begin(); it != vec.end(); it++) // 不使用推导
for(auto it = vec.begin(); it != end(); it++) // 使用推导

auto i = 5; // i被推导为int
auto j = new auto(5); // j 被推导为int

错误用法:

1
2
3
4
int foo(auto i,auto j); // 传参数,类型未定义,无法重载,无法通过编译

int ary[5] = {0};
auto ary1 = ary; // 无法推导数组

decltype

为了解决auto只能对变量推导的缺陷,所以decltype的用法是 decltype(表达是)

1
2
3
auto i = 4;
auto j = 5;
decltype(i+j) x; // int类型

拖尾类型返回

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
template<typename R,typename T,typename U>  //返回类型也要指定
R add(T x,U y) {
return x+y;
}

template<typename T,typename U> //无法编译通过, 期待自动推导,但是x,y未定义
decltype(x+y) add(T x,U y) {
return x+y;
}

template<typename T,typename U>
auto add(T x,U y) -> decltype(x+y) // C++11 需要通过拖尾类型返回实现
{
return x+y
}

template<typename T,typename U>
auto add(T x,U y) { // C++14 直接支持
return x+y
}

区间迭代

常见用法:

1
2
3
4
5
for (vector<int>::const_iterator it = vec.begin(); it != vec.end(); it++) // 不使用推导
for (auto &i: vec)
{
cout << i << endl;
}

初始化列表

c++提供了统一的语法初始化任意的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct A {
int a;
float b;
};

struct B {
B(int _a,float _b): a(_a),b(_b) {}
private:
int a;
float b;
};

A a{1,1.1};
B b{2,2.2};

模板增强

尖括号 “>”

在传统 C++ 的编译器中,>>一律被当做右移运算符来进行处理。C++11 开始,连续的右尖括号将变得合法,并且能够顺利通过编译。

1
std::vector<std::vector<int>> wow;

构造函数

委托构造

构造函数可以在同一个类中一个构造函数调用另一个构造函数

1
2
3
4
5
6
7
8
9
10
11
class Base {
public:
int value1;
int value2;
Base() {
value1 = 1;
}
Base(int value) : Base() { // 委托 Base() 构造函数
value2 = 2;
}
};

继承构造

使用继承构造之前

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct A
{
A(int i) {}
A(double d,int i){}
A(float f,int i,const char* c){}
//...等等系列的构造函数版本
};
struct B:A
{
B(int i):A(i){}
B(double d,int i):A(d,i){}
B(folat f,int i,const char* c):A(f,i,e){}
//......等等好多个和基类构造函数对应的构造函数
};

C++11的继承构造后

1
2
3
4
5
6
7
8
9
10
11
12
13
struct A
{
A(int i) {}
A(double d,int i){}
A(float f,int i,const char* c){}
//...等等系列的构造函数版本
};
struct B:A
{
using A::A;
//关于基类各构造函数的继承一句话搞定
//......
};

Lambda 表达式

Lambda 表达式,实际上就是提供了一个类似匿名函数的特性

1
[ caputrue ] ( params ) opt -> ret { body; };
  1. capture是捕获列表;
  2. params是参数表;(选填)
  3. opt是函数选项;可以填mutable,exception,attribute(选填)
    mutable说明lambda表达式体内的代码可以修改被捕获的变量,并且可以访问被捕获的对象的non-const方法。
    exception说明lambda表达式是否抛出异常以及何种异常。
    attribute用来声明属性。
  4. ret是返回值类型(拖尾返回类型)。(选填)
  5. body是函数体。

捕获列表:lambda表达式的捕获列表精细控制了lambda表达式能够访问的外部变量,以及如何访问这些变量。

1) []不捕获任何变量。
2) [&]捕获外部作用域中所有变量,并作为引用在函数体中使用(按引用捕获)。

3) [=]捕获外部作用域中所有变量,并作为副本在函数体中使用(按值捕获)。注意值捕获的前提是变量可以拷贝,且被捕获的变量在 lambda 表达式被创建时拷贝,而非调用时才拷贝。如果希望lambda表达式在调用时能即时访问外部变量,我们应当使用引用方式捕获。

1
2
3
4
5
6
7
8
9
int a = 0;
auto f = [=] { return a; }; //在函数内,拷贝一份a的值,所以无法改变他的值
a+=1;
cout << f() << endl; //输出0

int a = 0;
auto f = [&a] { return a; }; // 在函数内,引用外部变量,可以改变他的值
a+=1;
cout << f() <<endl; //输出1

4) [=,&foo]按值捕获外部作用域中所有变量,并按引用捕获foo变量。
5) [bar]按值捕获bar变量,同时不捕获其他变量。

6) [this]捕获当前类中的this指针,让lambda表达式拥有和当前类成员函数同样的访问权限。如果已经使用了&或者=,就默认添加此选项。捕获this的目的是可以在lamda中使用当前类的成员函数和成员变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class A
{
public:
int i_ = 0;

void func(int x,int y){
auto x1 = [] { return i_; }; //error,没有捕获外部变量
auto x2 = [=] { return i_ + x + y; }; //OK
auto x3 = [&] { return i_ + x + y; }; //OK
auto x4 = [this] { return i_; }; //OK
auto x5 = [this] { return i_ + x + y; }; //error,没有捕获x,y
auto x6 = [this, x, y] { return i_ + x + y; }; //OK
auto x7 = [this] { return i_++; }; //OK
};

int a=0 , b=1;
auto f1 = [] { return a; }; //error,没有捕获外部变量
auto f2 = [&] { return a++ }; //OK
auto f3 = [=] { return a; }; //OK
auto f4 = [=] {return a++; }; //error,a是以复制方式捕获的,无法修改
auto f5 = [a] { return a+b; }; //error,没有捕获变量b
auto f6 = [a, &b] { return a + (b++); }; //OK
auto f7 = [=, &b] { return a + (b++); }; //OK

注意f4,虽然按值捕获的变量值均复制一份存储在lambda表达式变量中,修改他们也并不会真正影响到外部,但我们却仍然无法修改它们。如果希望去修改按值捕获的外部变量,需要显示指明lambda表达式为mutable。被mutable修饰的lambda表达式就算没有参数也要写明参数列表。

原因:lambda表达式可以说是就地定义仿函数闭包的“语法糖”。它的捕获列表捕获住的任何外部变量,最终会变为闭包类型的成员变量。按照C++标准,lambda表达式的operator()默认是const的,一个const成员函数是无法修改成员变量的值的。而mutable的作用,就在于取消operator()的const。

1
2
3
int a = 0;
auto f1 = [=] { return a++; }; //error
auto f2 = [=] () mutable { return a++; }; //OK

lambda表达式是不能被赋值的:

1
2
3
4
5
auto a = [] { cout << "A" << endl; };
auto b = [] { cout << "B" << endl; };

a = b; // 非法,lambda无法赋值
auto c = a; // 合法,生成一个副本

闭包类型禁用了赋值操作符,但是没有禁用复制构造函数,所以你仍然可以用一个lambda表达式去初始化另外一个lambda表达式而产生副本。

在多种捕获方式中,最好不要使用[=]和[&]默认捕获所有变量。

1
2
3
4
std::function<int(int)> add_x(int x)
{
return [&](int a) { return x + a; };
}

悬挂引用,返回了一个lambda表达式,参数x仅是一个临时变量,函数add_x调用后就被销毁了,但是返回的lambda表达式却引用了该变量,当调用这个表达式时,引用的是一个垃圾值,会产生没有意义的结果。

采用默认值捕获所有变量仍然有风险

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Filter
{
public:
Filter(int divisorVal):
divisor{divisorVal}
{}

std::function<bool(int)> getFilter()
{
return [=](int value) {return value % divisor == 0; };
}

private:
int divisor;
};

这个类中有一个成员方法,可以返回一个lambda表达式,这个表达式使用了类的数据成员divisor。而且采用默认值方式捕捉所有变量。lambda表达式无法捕捉divisor的副本,因为数据成员divisor对lambda表达式并不可见

错误

1
2
3
4
std::function<bool(int)> getFilter() 
{
return [divisor](int value) {return value % divisor == 0; };
}

正确

1
2
3
4
std::function<bool(int)> getFilter() 
{
return [this](int value) {return value % this->divisor == 0; };
}

实现函数回调,类似函数指针

1
std::function<bool(int, int)> wrapper = [](int x, int y) { return x < y; };

最常用的是在STL算法中

1
2
3
int value = 3;
vector<int> v {1, 3, 5, 2, 6, 10};
int count = std::count_if(v.beigin(), v.end(), [value](int x) { return x > value; });

生成斐波那契数列,然后保存在数组中

1
2
3
4
5
vector<int> v(10);
int a = 0;
int b = 1;
std::generate(v.begin(), v.end(), [&a, &b] { int value = b; b = b + a; a = value; return value; });
// 此时v {1, 1, 2, 3, 5, 8, 13, 21, 34, 55}

当需要遍历容器并对每个元素进行操作时

1
2
3
4
5
6
7
8
std::vector<int> v = { 1, 2, 3, 4, 5, 6 };
int even_count = 0;
for_each(v.begin(), v.end(), [&even_count](int val){
if(!(val & 1)){
++ even_count;
}
});
std::cout << "The number of even is " << even_count << std::endl;

新增容器

std::array

std::forward_list

无序容器

元组 std::tuple

std::make_tuple: 构造元组
std::get: 获得元组某个位置的值
std::tie: 元组拆包

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
#include <tuple>
#include <iostream>

auto get_student(int id)
{
// 返回类型被推断为 std::tuple<double, char, std::string>
if (id == 0)
return std::make_tuple(3.8, 'A', "张三");
if (id == 1)
return std::make_tuple(2.9, 'C', "李四");
if (id == 2)
return std::make_tuple(1.7, 'D', "王五");
return std::make_tuple(0.0, 'D', "null");
// 如果只写 0 会出现推断错误, 编译失败
}

int main()
{
auto student = get_student(0);
std::cout << "ID: 0, "
<< "GPA: " << std::get<0>(student) << ", "
<< "成绩: " << std::get<1>(student) << ", "
<< "姓名: " << std::get<2>(student) << '\n';

double gpa;
char grade;
std::string name;

// 元组进行拆包
std::tie(gpa, grade, name) = get_student(1);
std::cout << "ID: 1, "
<< "GPA: " << gpa << ", "
<< "成绩: " << grade << ", "
<< "姓名: " << name << '\n';
}

正则表达式

  1. 检查一个串是否包含某种形式的子串;
  2. 将匹配的子串替换;
  3. 从某个串中取出符合条件的子串。
1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
#include <string>
#include <regex>

int main() {
std::string fnames[] = {"foo.txt", "bar.txt", "test", "a0.txt", "AAA.txt"};
// 在 C++ 中 `\` 会被作为字符串内的转义符,为使 `\.` 作为正则表达式传递进去生效,需要对 `\` 进行二次转义,从而有 `\\.`
std::regex txt_regex("[a-z]+\\.txt");
for (const auto &fname: fnames)
std::cout << fname << ": " << std::regex_match(fname, txt_regex) << std::endl;
}

语言级线程支持

std::mutex/std::unique_lock
std::future/std::packaged_task
std::condition_variable

代码编译需要使用 -pthread 选项

右值引用&&

  1. 消除两个对象交互时不必要的对象拷贝,节省运算存储资源,提高效率。
  2. 能够更简洁明确地定义泛型函数。
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
class MyString {
private:
char* _data;
size_t _len;
void _init_data(const char *s) {
_data = new char[_len + 1];
memcpy(_data, s, _len);
_data[_len] = '\0';
}
public:
MyString() {
_data = NULL;
_len = 0;
}

MyString(const char* p) {
_len = strlen(p);
_init_data(p);
}

MyString(const MyString& str) {
_len = str._len;
_init_data(str._data);
std::cout << "Copy Constructor is called! source: " << str._data << std::endl;
}

MyString& operator=(const MyString& str) {
if (this != &str) {
_len = str._len;
_init_data(str._data);
}
std::cout << "Copy Assignment is called! source: " << str._data << std::endl;
return *this;
}

virtual ~MyString() {
if (_data != NULL) {
std::cout << "Destructor is called! " << std::endl;
free(_data);
}
}
};

int main() {
MyString a;
a = MyString("Hello"); // 此处赋值函数
std::vector<MyString> vec;
vec.push_back(MyString("World")); // 此处拷贝构造函数
}

运行结果

1
2
3
4
5
6
Copy Assignment is called! source: Hello
Destructor is called!
Copy Constructor is called! source: World
Destructor is called!
Destructor is called!
Destructor is called!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
MyString(MyString&& str) {  //转移构造函数
std::cout << "Move Constructor is called! source: " << str._data << std::endl;
_len = str._len;
_data = str._data;
str._len = 0;
str._data = NULL; // ! 防止在析构函数中将内存释放掉
}

MyString& operator=(MyString&& str) { //转移赋值操作符重载
std::cout << "Move Assignment is called! source: " << str._data << std::endl;
if (this != &str) {
_len = str._len;
_data = str._data;
str._len = 0;
str._data = NULL; // ! 防止在析构函数中将内存释放掉
}
return *this;
}

注:右值引用并不能阻止编译器在临时对象使用完之后将其释放掉的事实,所以转移构造函数和转移赋值操作符重载函数 中都将_data赋值为了NULL,而且析构函数中保证了_data != NULL才会释放。

std::move

std::move并不能移动任何东西,它唯一的功能是将一个左值强制转化为右值引用,继而可以通过右值引用使用该值,以用于移动语义。从实现上讲,std::move基本等同于一个类型转换:static_cast<T&&>(lvalue)

  1. C++ 标准库使用比如vector::push_back 等这类函数时,会对参数的对象进行复制,连数据也会复制.这就会造成对象内存的额外创建, 本来原意是想把参数push_back进去就行了,通过std::move,可以避免不必要的拷贝操作。
  2. std::move是将对象的状态或者所有权从一个对象转移到另一个对象,只是转移,没有内存的搬迁或者内存拷贝所以可以提高利用效率,改善性能.。
  3. 对指针类型的标准库对象并不需要这么做.

命名对象使用 std::move右值引用

既然编译器只对右值引用才能调用转移构造函数和转移赋值函数,又因为所有命名对象都只能是左值引用。 在这样的条件了,如果已知一个命名对象不再被使用而想对它调用转移构造函数和转移赋值函数,也就是把一个左值引用当做右值引用来使用,怎么做呢?标准库提供了函数 std::move,这个函数以非常简单的方式将左值引用转换为右值引用。

1
2
3
4
5
6
7
8
9
10
11
12
13
void ProcessValue(int& i) { 
std::cout << "LValue processed: " << i << std::endl;
}

void ProcessValue(int&& i) {
std::cout << "RValue processed: " << i << std::endl;
}

int main() {
int a = 0;
ProcessValue(a);
ProcessValue(std::move(a)); // 命名对象使用右值引用
}

运行结果:

1
2
LValue processed: 0 
RValue processed: 0

std::move在提高 swap 函数的的性能上非常有帮助

1
2
3
4
5
6
7
template<class T>
void swap(T& a, T& b)
{
T tmp(a);
a = b; // copy
b = tmp;
}
1
2
3
4
5
6
7
template<class T>
void swap(T& a,T& b)
{
T tmp(std::move(a));
a = std::move(b); // move
b = std::move(tmp);
}

使用右值引用精确传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
template<typename T>
void forward_value(const T& val)
{
process_value(val);
}

template<typename T>
void forward_value(T& val)
{
process_value(val);
}

int a = 0;
const int &b = 1;
// 为了实现const T& 和T&必须重载
forward_value(a); // int&
forward_value(b); // const int&
forward_value(2); // int&

为了解决这种情况,使用右值引用

1
2
3
4
5
template<typename T>
void forward_value(T&& val)
{
process_value(val);
}

智能指针

智能指针在C++11版本之后提供,包含在头文件中,shared_ptr、unique_ptr、weak_ptr

shared_ptr

shared_ptr多个指针指向相同的对象。shared_ptr使用引用计数,每一个shared_ptr的拷贝都指向相同的内存。每使用他一次,内部的引用计数加1,每析构一次,内部的引用计数减1,减为0时,自动删除所指向的堆内存。shared_ptr内部的引用计数是线程安全的,但是对象的读取需要加锁。

  • 初始化。智能指针是个模板类,可以指定类型,传入指针通过构造函数初始化。也可以使用make_shared函数初始化。不能将指针直接赋值给一个智能指针,一个是类,一个是指针。例如std::shared_ptr p4 = new int(1);的写法是错误的
  • 拷贝和赋值。拷贝使得对象的引用计数增加1,赋值使得原对象引用计数减1,当计数为0时,自动释放内存。后来指向的对象引用计数加1,指向后来的对象。
  • get函数获取原始指针
  • 注意不要用一个原始指针初始化多个shared_ptr,否则会造成二次释放同一内存
  • 注意避免循环引用,shared_ptr的一个最大的陷阱是循环引用,循环,循环引用会导致堆内存无法正确释放,导致内存泄漏。循环引用在weak_ptr中介绍。
unique_ptr

unique_ptr“唯一”拥有其所指对象,同一时刻只能有一个unique_ptr指向给定对象(通过禁止拷贝语义、只有移动语义来实现),unique_ptr指针与其所指对象的关系:在智能指针生命周期内,可以改变智能指针所指对象,如创建智能指针时通过构造函数指定、通过reset方法重新指定、通过release方法释放所有权、通过移动语义转移所有权。

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <memory>

int main() {
{
std::unique_ptr<int> uptr(new int(10)); //绑定动态对象
//std::unique_ptr<int> uptr2 = uptr; //不能賦值
//std::unique_ptr<int> uptr2(uptr); //不能拷貝
std::unique_ptr<int> uptr2 = std::move(uptr); //轉換所有權
uptr2.release(); //释放所有权
}
//超過uptr的作用域,內存釋放
}
weak_ptr

weak_ptr是为了配合shared_ptr而引入的一种智能指针,因为它不具有普通指针的行为,没有重载operator*和->,它的最大作用在于协助shared_ptr工作,像旁观者那样观测资源的使用情况。

weak_ptr可以从一个shared_ptr或者另一个weak_ptr对象构造,获得资源的观测权。但weak_ptr没有共享资源,它的构造不会引起指针引用计数的增加。

使用weak_ptr的成员函数use_count()可以观测资源的引用计数,另一个成员函数expired()的功能等价于use_count()==0,但更快,表示被观测的资源(也就是shared_ptr的管理的资源)已经不复存在。weak_ptr可以使用一个非常重要的成员函数lock()从被观测的shared_ptr获得一个可用的shared_ptr对象, 从而操作资源。但当expired()==true的时候,lock()函数将返回一个存储空指针的shared_ptr。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <memory>

int main() {
{
std::shared_ptr<int> sh_ptr = std::make_shared<int>(10);
std::cout << sh_ptr.use_count() << std::endl; // 1

std::weak_ptr<int> wp(sh_ptr);
std::cout << wp.use_count() << std::endl; // 1

if(!wp.expired()){
std::shared_ptr<int> sh_ptr2 = wp.lock(); //get another shared_ptr
*sh_ptr = 100;
std::cout << wp.use_count() << std::endl; // 2
}
}
//delete memory
}

std::function

  • std::function 是一个可调用对象包装器,是一个类模板,可以容纳除了类成员函数指针之外的所有可调用对象,它可以用统一的方式处理函数、函数对象、函数指针,并允许保存和延迟它们的执行。

  • 定义格式:std::function<函数类型>。

  • std::function可以取代函数指针的作用,因为它可以延迟函数的执行,特别适合作为回调函数使用。它比普通函数指针更加的灵活和便利。

std::bind

可将std::bind函数看作一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来“适应”原对象的参数列表。

std::bind将可调用对象与其参数一起进行绑定,绑定后的结果可以使用std::function保存。std::bind主要有以下两个作用:

  • 将可调用对象和其参数绑定成一个防函数;

  • 只绑定部分参数,减少可调用对象传入的参数。

    注意:

  • (1)bind预先绑定的参数需要传具体的变量或值进去,对于预先绑定的参数,是pass-by-value的

  • (2)对于不事先绑定的参数,需要传std::placeholders进去,从_1开始,依次递增。placeholder是pass-by-reference的

  • (3)bind的返回值是可调用实体,可以直接赋给std::function对象

  • (4)对于绑定的指针、引用类型的参数,使用者需要保证在可调用实体调用之前,这些参数是可用的

  • (5)类的this可以通过对象或者指针来绑定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int Func(int x, int y);
auto bf1 = std::bind(Func, 10, std::placeholders::_1);
bf1(20); ///< same as Func(10, 20)

int HelloWorld::AddFunc( int a, int b )
{
return a + b;
}

bool HelloWorld::init()
{

auto bf2 = std::bind(&HelloWorld::AddFunc,this , std::placeholders::_1, std::placeholders::_2 );
auto result1 = bf2(10, 20); ///< same as a.Func(10, 20)

std::function< int(int)> bf3 = std::bind(&HelloWorld::AddFunc, this, std::placeholders::_1, 100);
auto result2 = bf3(10); ///< same as a.Func(10, 100)

}
1
2
3
4
double my_divide (double x, double y) {return x/y;}
// bind的第一个参数是函数名,普通函数做实参时,会隐式转换成函数指针,因此std::bind (my_divide,_1,2)等价于std::bind (&my_divide,_1,2);
auto fn_half = std::bind (my_divide,_1,2); //减少参数,_1表示占位符,位于<functional>中,std::placeholders::_1;
std::cout << fn_half(10) << '\n';
1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct Foo {
void print_sum(int n1, int n2)
{
std::cout << n1+n2 << '\n';
}
int data = 10;
};
int main()
{
Foo foo;
// bind绑定类成员函数时,第一个参数表示对象的成员函数的指针,第二个参数表示对象的地址。
auto f = std::bind(&Foo::print_sum, &foo, 95, std::placeholders::_1);
f(5); // 100
}

std::forward

需要一种方法能够按照参数原来的类型转发到另一个函数,这种转发类型称为完美转发。

完美转发(Perfect Forwarding),是指在函数模板中,完全依照模板的参数的类型(即保持参数的左值、右值特征),将参数传递给函数模板中调用的另外一个函数。C++11中提供了这样的一个函数std::forward,它是为转发而生的,不管参数是T&&这种未定的引用还是明确的左值引用或者右值引用,它会按照参数本来的类型转发。

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

#include<iostream>
using namespace std;
template<typename T>
void print(T& t)
{
cout << "lvalue" << endl;
}

template<typename T>
void print(T&& t)
{
cout << "rvalue" << endl;
}

template<typename T>
void TestForward(T && v)
{
//print(v); //编译错误 不知道是哪个print
print(std::forward<T>(v));
print(std::move(v));
}

int main()
{
TestForward(1);
int x = 1;
//TestForward(x); //使print(std::forward<T>(v));编译错误
TestForward(std::forward<int>(x));
return 0;
}
//rvalue
//rvalue
//rvalue
//rvalue

std::move没有move任何东西,std::forward没有转发任何东西。在运行期,它们没有做任何事情。它们没有产生需要执行的代码,一byte都没有。

std::move和std::forward只不过就是执行cast的两个函数(实际上是函数模板)。std::move无条件地把它的参数转换成一个右值,而std::forward只在特定条件满足的情况下执行这个转换。

delete

1
为了能够让程序员显式的禁用某个函数,C++11 标准引入了一个新特性:"=delete"函数。程序员只需在函数声明后上“=delete;”,就可将该函数禁用。
1
2
3
4
5
6
7
class MyClass
{
public:
MyClass()=default; //该函数比用户自己定义的默认构造函数获得更高的代码效率
MyClass(const MyClass& )=delete;
......
}

enable_shared_from_this

定义

std::enable_shared_from_this 能让一个对象(假设其名为 t ,且已被一个 std::shared_ptr 对象 pt 管理)安全地生成其他额外的 std::shared_ptr 实例(假设名为 pt1, pt2, … ) ,它们与 pt 共享对象 t 的所有权。

若一个类 T 继承 std::enable_shared_from_this ,则会为该类 T 提供成员函数: shared_from_this 。 当 T 类型对象 t 被一个为名为 pt 的 std::shared_ptr 类对象管理时,调用 T::shared_from_this 成员函数,将会返回一个新的 std::shared_ptr 对象,它与 pt 共享 t 的所有权。

使用场合

当类A被share_ptr管理,且在类A的成员函数里需要把当前类对象作为参数传给其他函数时,就需要传递一个指向自身的share_ptr。

  1. 为何不直接传递this指针

​ 使用智能指针的初衷就是为了方便资源管理,如果在某些地方使用智能指针,某些地方使用原始指针,很容易破坏智能指针的语义,从而产生各种错误。

  1. 可以直接传递share_ptr么?

    答案是不能,因为这样会造成2个非共享的share_ptr指向同一个对象,未增加引用计数导对象被析构两次。

    错误:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    #include <memory>
    #include <iostream>

    class Bad
    {
    public:
    std::shared_ptr<Bad> getptr() {
    return std::shared_ptr<Bad>(this);
    }
    ~Bad() { std::cout << "Bad::~Bad() called" << std::endl; }
    };

    int main()
    {
    // 错误的示例,每个shared_ptr都认为自己是对象仅有的所有者
    std::shared_ptr<Bad> bp1(new Bad());
    std::shared_ptr<Bad> bp2 = bp1->getptr();
    // 打印bp1和bp2的引用计数
    std::cout << "bp1.use_count() = " << bp1.use_count() << std::endl;
    std::cout << "bp2.use_count() = " << bp2.use_count() << std::endl;
    } // Bad 对象将会被删除两次

    正确:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24

    #include <memory>
    #include <iostream>

    struct Good : std::enable_shared_from_this<Good> // 注意:继承
    {
    public:
    std::shared_ptr<Good> getptr() {
    return shared_from_this();
    }
    ~Good() { std::cout << "Good::~Good() called" << std::endl; }
    };

    int main()
    {
    // 大括号用于限制作用域,这样智能指针就能在system("pause")之前析构
    {
    std::shared_ptr<Good> gp1(new Good());
    std::shared_ptr<Good> gp2 = gp1->getptr();
    // 打印gp1和gp2的引用计数
    std::cout << "gp1.use_count() = " << gp1.use_count() << std::endl;
    std::cout << "gp2.use_count() = " << gp2.use_count() << std::endl;
    }
    system("pause");

    为何会出现这种使用场合

    ​ 因为在异步调用中,存在一个保活机制,异步函数执行的时间点我们是无法确定的,然而异步函数可能会使用到异步调用之前就存在的变量。为了保证该变量在异步函数执期间一直有效,我们可以传递一个指向自身的share_ptr给异步函数,这样在异步函数执行期间share_ptr所管理的对象就不会析构,所使用的变量也会一直有效了(保活)。

mutable

在C++中,mutable也是为了突破const的限制而设置的。被mutable修饰的变量,将永远处于可变的状态,即使在一个const函数中。

我们知道,被const关键字修饰的函数的一个重要作用就是为了能够保护类中的成员变量。即:该函数可以使用类中的所有成员变量,但是不能修改他们的值。然而,在某些特殊情况下,我们还是需要在const函数中修改类的某些成员变量,因为要修改的成员变量与类本身并无多少关系,即使修改了也不会对类造成多少影响。当然,你可以说,你可以去掉该函数的const关键字呀!但问题是,我只想修改某个成员变量,其余成员变量仍然希望被const保护。

using各种用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*定义别名*/
template<class T>
using Tlist = std::list<T>;

using Tlist = std::list<char>;
Tlist listChar;

//typedef void (*df)()
using df = void(*)();
/*使用外部构造*/
using A::A;

/*引用外部类型*/
using typename A;

不想要使用默认的拷贝构造函数或赋值函数

1.新增auto、decltype关键字,二者相似又有区别
  2.新增char16_t、char32_t、long long int类型
  3.新增constexpr编译时常量表达式
  4.新增default、delete、override、final说明符
  5.新增delegating constructors委托构造函数
  6.新增std::initializer_list初始化列表、uniform initialization统一初始化

  7.新增Enum class枚举类、extend templates拓展模板、type可用于模板
  8.新增Lambda表达式
  9.新增nullptr、foreach、r-value右值,tuple元组
  10.新增移动意义,包括move constructor移动构造、move assign移动赋值
  11.新增static_assert编译时检查
  12.新增智能指针std::unique_ptr、std::share_ptr、std::weak_ptr,废弃std::auto_ptr

C++14新特性:

  1.新增聚合成员初始化
  2.新增二进制文字、数字分隔符
  3.废弃attribute
  4.新增函数返回值推断
  5.新增constexpr函数
  6.新增变体模板
  7.新增标准用户定义的文字
  8.新增std::make_unique,用于创建std::unique_ptr、

参考信息

C++2a 功能特性 提案 版本 GCC Clang MSVC EDG eccp Intel C++ IBM XLC++ Sun/Oracle C++ Embarcadero C++ Builder Cray Portland Group (PGI) [折叠]
允许 lambda 捕获 [=, this] P0409R2 c++2a-lang 8 6 5.1
__VA_OPT__ P0306R4 c++2a-lang 8 (部分)* 6 5.1
指派初始化器 P0329R4 c++2a-lang 4.7 (部分)* 8 3.0 (部分)* 5.1
泛型 lambda 的模板形参列表 P0428R2 c++2a-lang 8 5.1
位域的默认成员初始化器 P0683R1 c++2a-lang 8 6 5.1
类模板实参推导中的 initializer_list 构造函数 P0702R1 c++2a-lang 8 6 19.14* 5.0
const& 限定的成员指针 P0704R1 c++2a-lang 8 6 5.1
概念 (concept) P0734R0 c++2a-lang 6 (仅 TS)
不求值语境中的 lambda P0315R4 c++2a-lang 9
三路比较运算符 P0515R3 c++2a-lang 8 (部分)* 19.20*
简化隐式 lambda 捕获 P0588R1 c++2a-lang 8
基于范围的 for 的初始化语句 P0614R1 c++2a-lang 9 8
可默认构造且可赋值的无状态 lambda P0624R2 c++2a-lang 9 8 5.1
与预置的复制构造函数的 const 不匹配 P0641R2 c++2a-lang 9 8 5.1
特化上的访问检查 P0692R1 c++2a-lang 是 8 (部分)*
ADL 与不可见的函数模板 P0846R0 c++2a-lang 9
令 constexpr 函数的实例化较不贪婪 P0859R0 c++2a-lang 5.2 (部分)* 9
属性 [[likely]] 与 [[unlikely]] P0479R5 c++2a-lang 9 5.1
使 typename 更可选 P0634R3 c++2a-lang 9
Lambda 初始化捕获中的包展开 P0780R2 c++2a-lang 9
属性 [[no_unique_address]] P0840R2 c++2a-lang 9 5.1
契约 P0542R5 c++2a-lang
销毁的 operator delete P0722R3 c++2a-lang 9 6
非类型模板形参中的类类型 P0732R2 c++2a-lang 9
explicit(bool) P0892R2 c++2a-lang 9 5.1
整合功能特性测试宏 P0941R2 c++2a-lang 5 3.4 19.15* 5.0
禁止聚合体有用户声明的构造函数 P1008R1 c++2a-lang 9 8 5.1
constexpr 虚函数 P1064R0 c++2a-lang 9 5.1
char8_t P0482R6 c++2a-lang 9 7
std::is_constant_evaluated() P0595R2 c++2a-lang 9
constexpr try-catch 代码块 P1002R1 c++2a-lang 9 8 5.1
立即函数 P1073R3 c++2a-lang 5.1
嵌套内联命名空间 P1094R2 c++2a-lang 9 8 5.1
constexpr 的 dynamic_cast 和多态 typeid P1327R1 c++2a-lang 5.1
在 constexpr 中改变联合体的活跃成员 P1330R0 c++2a-lang 9 5.1
结构化绑定的扩展 P1091R3 P1381R1 c++2a-lang
更强的 Unicode 要求 P1041R4 P1139R2 c++2a-lang 是
参数化的聚合体初始化 P0960R3 c++2a-lang
模块 (module) P1103R3 c++2a-lang 8 (部分)
协程 (coroutine) P0912R5 c++2a-lang 8 (部分)
std::endian P0463R1 c++2a 8 7 N/A
std::remove_cvref P0550R2 c++2a 9 6 19.20* N/A
扩展 std::make_shared 以支持数组 P0674R1 c++2a N/A
原子性浮点算术 P0020R6 c++2a N/A
同步缓冲的 ostream P0053R7 c++2a N/A
与 的 constexpr P0202R3 c++2a 8 N/A
的更多 constexpr P0415R1 c++2a 9 N/A
字符串前缀与后缀检查 P0457R2 c++2a 9 6 N/A
operator<=> 的库支持 P0515R3 c++2a 7 19.20* N/A
转换指针为裸指针的工具 P0653R2 c++2a 8 6 N/A
原子性的 shared_ptr 与 weak_ptr P0718R2 c++2a N/A
std::span P0122R7 c++2a 7 N/A
日历与时区 P0355R7 c++2a 7 N/A
P0754R2 c++2a 9 7 N/A
std::atomic_ref P0019R8 c++2a N/A
整数的 2 的幂的运算 P0556R3 c++2a 9 N/A
std::bit_cast() P0476R2 c++2a N/A
std::destroying_delete P0722R3 c++2a 9 N/A
概念库 P0898R3 c++2a N/A
一致的容器擦除 P1209R0 c++2a 9 8 N/A
C++2a 功能特性 提案 版本 GCC Clang MSVC EDG eccp Intel C++ IBM XLC++ Sun/Oracle C++ Embarcadero C++ Builder Cray Portland Group (PGI)

C++17 功能特性

C++17 功能特性 提案 版本 GCC Clang MSVC EDG eccp Intel C++ IBM XLC++ Sun/Oracle C++ Embarcadero C++ Builder Cray Portland Group (PGI) [折叠]
直接列表初始化的新 auto 规则 N3922 c++17-lang 5 3.8 19.0* 4.10.1 17.0 17.7
无消息的 static_assert N3928 c++17-lang 6 2.5 19.10* 4.12 18.0 17.7
模板模板形参中的 typename N4051 c++17-lang 5 3.5 19.0* 4.10.1 17.0 17.7
移除三标符 N4086 c++17-lang 5 3.5 16.0* 5.0
嵌套命名空间定义 N4230 c++17-lang 6 3.6 19.0* 4.12 17.0 17.7
命名空间和枚举项的属性 N4266 c++17-lang 4.9 (命名空间) / 6 (枚举项) 3.6 19.0* 4.11 17.0 17.7
u8 字符字面量 N4267 c++17-lang 6 3.6 19.0* 4.11 17.0 17.7
允许所有非类型模板实参的常量求值 N4268 c++17-lang 6 3.6 19.12* 5.0
折叠表达式 N4295 c++17-lang 6 3.6 19.12* 4.14 19.0 18.1
移除 register 关键字的已弃用用法 P0001R1 c++17-lang 7 3.8 19.11* 4.13 18.0 17.7
移除已弃用的 operator++(bool) P0002R1 c++17-lang 7 3.8 19.11* 4.13 18.0 17.7
从 C++17 移除已弃用的异常规定 P0003R5 c++17-lang 7 4 19.10* 4.14 19.0
令异常规定为类型系统的一部分 P0012R1 c++17-lang 7 4 19.12* 4.14 19.0
有基类的类的聚合初始化 P0017R1 c++17-lang 7 3.9 19.14* 5.0
*this 的 lambda 捕获 P0018R3 c++17-lang 7 3.9 19.11* 4.14 19.0 18.1
使用属性命名空间而不重复 P0028R4 c++17-lang 7 3.9 19.11* 4.13 18.0 17.7
过对齐数据的动态内存分配 P0035R4 c++17-lang 7 4 19.12* 4.14
一元折叠表达式和空形参包 P0036R0 c++17-lang 6 3.9 19.12* 4.14
预处理器条件中的 __has_include P0061R1 c++17-lang 5 是 19.11* 4.13 18.0 17.7
类模板实参推导 P0091R3 c++17-lang 7 5 19.14* 5.0 19.1
具有 auto 类型的非类型模板形参 P0127R2 c++17-lang 7 4 19.14* 5.0 19.1
有保证的复制消除 P0135R1 c++17-lang 7 4 19.13* 5.0 19.1
继承构造函数的新规定 (DR1941 等) P0136R1 c++17-lang 7 3.9 19.14*
替换含引用成员的类对象 P0137R1 c++17-lang 7 6 19.14* 5.0
枚举的直接列表初始化 P0138R2 c++17-lang 7 3.9 19.11* 4.14 18.0
更严格的表达式求值顺序 P0145R3 c++17-lang 7 4 19.14* 5.0
constexpr lambda 表达式 P0170R1 c++17-lang 7 5 19.11* 4.14 19.0 18.1
基于范围 for 的相异 begin 和 end 类型 P0184R0 c++17-lang 6 3.9 19.10* 4.12 18.0 17.7
[[fallthrough]] 属性 P0188R1 c++17-lang 7 3.9 19.10* 4.13 18.0 17.7
[[nodiscard]] 属性 P0189R1 c++17-lang 7 3.9 19.11* 4.13 18.0 17.7
using 声明中的包展开 P0195R2 c++17-lang 7 4 19.14* 5.0
[[maybe_unused]] 属性 P0212R1 c++17-lang 7 3.9 19.11* 4.13 18.0 17.7
结构化绑定 P0217R3 c++17-lang 7 4 19.11* 4.14 19.0 18.1
十六进制浮点字面量 P0245R1 c++17-lang 3.0 是 19.11* 4.13 18.0 17.7
忽略未知属性 P0283R2 c++17-lang 是 3.9 19.11* 4.13 18.0 17.7
constexpr if 语句 P0292R2 c++17-lang 7 3.9 19.11* 4.14 19.0 18.1
if 和 switch 的初始化语句 P0305R1 c++17-lang 7 3.9 19.11* 4.14 18.0 18.1
内联变量 P0386R2 c++17-lang 7 3.9* 19.12* 4.14 19.0 18.1
DR :模板模板实参的匹配排除了兼容的模板 P0522R0 c++17-lang 7 4 19.12* 5.0
std::uncaught_exceptions N4259 c++17 6 3.7 19.0* N/A N/A N/A
改进 std::pair 和 std::tuple N4387 c++17 6 4 19.0* N/A N/A N/A
std::any P0220R1 c++17 7 4 19.10* N/A N/A N/A
std::variant P0088R3 c++17 7 4 19.10* N/A N/A N/A
std::optional P0220R1 c++17 7 4 19.10* N/A N/A N/A
std::shared_mutex (无时限) N4508 c++17 6 3.7 19.0* N/A N/A N/A
std::string_view N3921 c++17 7 4 19.10* N/A N/A N/A
并行 TS 的标准化 P0024R2 c++17 19.14* (部分) N/A 18.0* N/A
C++17 应当指代 C11 而不是 C99 P0063R3 c++17 9 7 19.0* (部分)* N/A N/A N/A
初等字符串转换 P0067R5 c++17 8 (无浮点) 19.14(无浮点) 19.15 N/A N/A N/A
数学特殊函数 P0226R1 c++17 7 19.14* N/A N/A N/A
接合 map 和 set P0083R3 c++17 7 8 19.12* N/A N/A N/A
硬件干涉大小 P0154R1 c++17 19.11* N/A N/A N/A
std::filesystem P0218R1 c++17 8 7 19.14* N/A N/A N/A
std::byte P0298R3 c++17 7 5 19.11* N/A N/A N/A
C++17 功能特性 提案 版本 GCC Clang MSVC EDG eccp Intel C++ IBM XLC++ Sun/Oracle C++ Embarcadero C++ Builder Cray Portland Group (PGI)

C++14 功能特性

C++14 功能特性 提案 版本 GCC Clang MSVC EDG eccp Intel C++ IBM XLC++ Sun/Oracle C++ Embarcadero C++ Builder Cray Portland Group (PGI) [折叠]
按语境转换的遣词调整 N3323 c++14-lang 4.9 3.4 18.0* 4.9 16.0 13.1.2* 5.15 8.6 16.1
二进制字面量 N3472 c++14-lang 4.3/4.9 2.9 19.0* 4.10 11.0 13.1.2* 5.14 8.6 2015
decltype(auto) ,普通函数的返回类型推导 N3638 c++14-lang 4.8/4.9 3.3/3.4 19.0* 4.9 15.0 13.1.2* 5.15 8.6 16.1
带初始化/泛化的 lambda 捕获 (init-capture) N3648 c++14-lang 4.5/4.9 3.4 19.0* 4.10 15.0 5.15 8.6 16.1
泛型(多态) lambda 表达式 N3649 c++14-lang 4.9 3.4 19.0* 4.10 16.0 13.1.2* 5.15 8.6 16.1
变量模板 N3651 c++14-lang 5 3.4 19.0* 4.11 17.0 13.1.2* 5.15 8.6 17.4
扩展的 constexpr N3652 c++14-lang 5 3.4 19.10* 4.11 17.0 13.1.2* 5.15 8.6 17.4
成员初始化器与聚合体 (NSDMI) N3653 c++14-lang 5 3.3 19.10* 4.9 16.0 5.14 8.6 16.1
澄清内存分配(分配的免除/融合) N3664 c++14-lang N/A 3.4 N/A N/A N/A 8.6 17.4
[[deprecated]] 属性 N3760 c++14-lang 4.9 3.4 19.0* 4.9 15.0* 16.0 13.1.2* 5.14 8.6 16.1
具大小解分配 N3778 c++14-lang 5 3.4 19.0* 4.10.1 17.0 5.14 8.6 16.1
单引号作为数位分隔符 N3781 c++14-lang 4.9 3.4 19.0* 4.10 16.0 13.1.2* 5.14 8.6 2015
std::result_of 与 SFINAE N3462 c++14 5 是 19.0* N/A N/A 5.15 是 8.6 N/A
的 constexpr N3302 c++14 5 3.4 19.0* N/A N/A 5.15 8.6 N/A
的 constexpr N3469 c++14 5 3.4 19.0* N/A N/A 5.15 8.6 N/A
的 constexpr N3470 c++14 5 3.4 19.0* N/A N/A 5.15 8.6 N/A
、 和 的 constexpr N3471 c++14 5 3.4 19.0* N/A N/A 5.15 8.6 N/A
改进的 std::integral_constant N3545 c++14 5 3.4 19.0* N/A N/A 5.15 8.6 N/A
和 的用户定义字面量 N3642 c++14 5 3.4 19.0* N/A N/A 5.15 8.6 N/A
空向前迭代器 N3644 c++14 5* 3.4 19.0* N/A N/A 5.15 8.6 N/A
std::quoted N3654 c++14 5 3.4 19.0* N/A N/A 5.15 8.6 N/A
异质关联查找 N3657 c++14 5 3.4 19.0* N/A N/A 5.15 8.6 N/A
std::integer_sequence N3658 c++14 5 3.4 19.0* N/A N/A 5.15 8.6 N/A
std::shared_timed_mutex N3659 c++14 5 3.4 19.0* N/A N/A 5.15 8.6 N/A
std::exchange N3668 c++14 5 3.4 19.0* N/A N/A 5.15 8.6 N/A
修正无 const 的 constexpr成员函数 N3669 c++14 5 3.4 19.0* N/A N/A 5.15 8.6 N/A
std::get() N3670 c++14 5 3.4 19.0* N/A N/A 5.15 8.6 N/A
双范围的 std::equal 、 std::is_permutation 、 std::mismatch N3671 c++14 5 3.4 19.0* N/A N/A 5.15 8.6 N/A
C++14 功能特性 提案 版本 GCC Clang MSVC EDG eccp Intel C++ IBM XLC++ Sun/Oracle C++ Embarcadero C++ Builder Cray Portland Group (PGI)

C++11 功能特性

C++11 功能特性 提案 版本 GCC Clang MSVC EDG eccp Intel C++ IBM XLC++ Sun/Oracle C++ Embarcadero C++ Builder Cray Portland Group (PGI) HP aCC Digital Mars C++ [折叠]
alignas N2341 c++11 4.8 3.0 19.0* 4.8 15.0 13.1.2* 5.13 是 8.6 2015
alignof N2341 c++11 4.5 2.9 19.0* 4.8 15.0 13.1.2* 5.13 是 8.4 2015
原子操作 N2427 c++11 4.4 3.1 17.0* Yes 13.0 13.1.2* 5.14 是 8.4 2015
auto N1984(v1.0) c++11 4.4(v1.0) 是 16.0* 3.9 11.0(v0.9) 12.0(v1.0) 11.1(v1.0) 5.13 是 8.4 2015 A.06.25
C99 预处理器 N1653 c++11 4.3 是 19.0* (部分:变参宏有漏洞) 4.1 11.1 10.1 5.9 是 8.4 2015 A.06.25 是
constexpr N2235 c++11 4.6 3.1 19.0* (部分) 4.6 13.0* 14.0 12.1* 13.1 5.13 是 8.4 2015 A.06.28
decltype v1.0: N2343v1.1: N3276 c++11 4.3(v1.0) 4.8.1(v1.1) 2.9 16.0* 4.2(v1.0) 4.8(v1.1) 11.0(v1.0) 12.0(v1.1) 11.1(v1.0) 5.13 是 8.4 2015 A.06.25 8.52(v1.0)
预置和弃置的函数 N2346 c++11 4.4 3.0 18.0* 4.1 12.0 13.1 5.13 是 8.4 2015 A.06.25
委托构造函数 N1986 c++11 4.7 3.0 18.0* 4.7 14.0 11.1 5.13 是 8.4 2015 A.06.28
显式转换运算符 N2437 c++11 4.5 3.0 18.0* 4.4 13.0 12.1 5.13 是 8.4 2015 A.06.27
扩展的 friend 声明 N1791 c++11 4.7 2.9 16.0* (部分) 18.0* 4.1 11.1* 12.0 11.1 5.13 是 8.4 2015 A.06.25
extern template N1987 c++11 3.3 是 12.0* 3.9 9.0 11.1 5.13 是 8.4 2015 A.06.25
前置 enum 声明 N2764 c++11 4.6 3.1 17.0* 4.5 11.1* 14.0 12.1 5.13 是 8.4 2015
继承的构造函数 N2540 c++11 4.8 3.3 19.0* 4.8 15.0 13.1.1* 5.13 是 8.4 2015
初始化器列表 N2672 c++11 4.4 3.1 18.0* 4.5 13.0* 14.0 13.1.2* 5.13 是 8.4 2015 A.06.28
Lambda 表达式 v0.9: N2550v1.0: N2658 v1.1: N2927 c++11 4.5(v1.1) 3.1 16.0(v1.0) 17.0(v1.1) 4.1(v1.1) 12.0(v1.1) 13.1.2* 5.13 是 8.4 2015 A.06.25
局部及无名类型作为模板形参 N2657 c++11 4.5 2.9 16.0* 4.2 12.0 13.1.2* 5.13 是 8.4 2015 A.06.27
long long N1811 c++11 是 是 14.0* 是 是 是 是 是 8.4 2015 是 是
内联命名空间 N2535 c++11 4.4 2.9 19.0* 4.5 14.0 11.1 5.13 是 8.4 2015 A.06.28
新字符类型 N2249 c++11 4.4 2.9 19.0* 4.4 12.1* 14.0 13.1.1* 5.13 是 8.4 2015 A.06.27 8.52
尾随的函数返回类型 N2541 c++11 4.4 2.9 16.0* 4.1 12.0 12.1 5.13 是 8.4 2015 A.06.27
nullptr N2431 c++11 4.6 2.9 16.0* 4.2 12.1 13.1 5.13 是 8.4 2015 A.06.27 8.52
Unicode 字符串字面量 N2442 c++11 4.4 3.0 19.0* 4.7 11.0* 10.1* 13.1.1* 5.7 是 8.4 2015 A.06.28 8.52
原始字符串字面量 N2442 c++11 4.5 是 18.0* 4.7 14.0 13.1.1* 5.13 是 8.4 2015 A.06.28 8.52
用户定义字面量 N2765 c++11 4.7 3.1 19.0* 4.8 15.0 13.1.2* 5.14 是 8.4 2015
右角括号 N1757 c++11 4.3 是 14.0* 4.1 11.0 12.1 5.13 是 8.4 2015
右值引用 v1.0: N2118v2.0: N2844 v2.1: N2844+ v3.0: N3053 c++11 4.3(v1.0) 4.5(v2.1) 4.6(v3.0) 是 16.0(v2.0) 17.0(v2.1) 19.0*(v3.0) 4.5(v3.0) 11.1(v1.0) 12.0(v2.0) 14.0(v3.0) 12.1(v2.1) 5.13 是 8.4 2015 A.06.25
static_assert N1720 c++11 4.3 2.9 16.0* 4.1 11.0 11.1 5.13 是 8.4 2015 A.06.25 8.52
强类型 enum N2347 c++11 4.4 2.9 17.0* 4.0 13.0 12.1 5.13 是 8.4 2015 A.06.25
模板别名 N2258 c++11 4.7 3.0 18.0* 4.2 12.1 13.1.1* 5.13 是 8.4 2015 A.06.27
线程局域存储 N2659 c++11 4.4* 4.8 3.3* 3.3 16.0* (部分) 19.0* 4.8 11.1* 15.0* 10.1* 13.1.2* 5.9* 是 8.4 2015 8.52*
无限制的联合体 N2544 c++11 4.6 3.0 19.0* 4.6 14.0* 13.1.2* 5.13 是 8.4 2015 A.06.28
类型特征 N1836 c++11 4.3 3.0 14.0* 4.0 10.0 13.1.3 5.13 是 8.4 2015 6.16
变参模板 v0.9: N2242v1.0: N2555 c++11 4.3(v0.9) 4.4(v1.0) 2.9(v1.0) 18.0* 4.3(v0.9) 4.3(v1.0) 12.1(v1.0) 11.1(v0.9) 5.13 是 8.4 2015 A.06.27
范围 for 循环 N2930 c++11 4.6 3.0 17.0* 4.5 13.0 13.1.2* 5.13 是 8.4 2015 A.06.28
override 与 final v0.8: N2928v0.9: N3206 v1.0: N3272 c++11 4.7 2.9 14.0* (部分) 17.0* 4.8(v1.0) 12.0(v0.8) 14.0(v1.0) 13.1.1* 5.13 是 8.4 2015
属性 N2761 c++11 4.8 3.3 19.0* 4.2 12.1 13.1.1* 5.13 是 8.4 2015 A.06.27
引用限定符 N2439 c++11 4.8.1 2.9 19.0* 4.7 14.0 13.1.2* 5.13 是 8.4 2015 A.06.28
非静态数据成员初始化器 N2756 c++11 4.7 3.0 18.0* 4.6 14.0 13.1.2* 5.13 是 8.4 2015 A.06.28
有并发的动态初始化及析构(魔法静态变量) N2660 c++11 4.3 2.9 19.0* 是 11.1* 13.1.2* 5.13 是 8.4 2015 A.06.25
noexcept N3050 c++11 4.6 3.0 19.0* 4.5 14.0 13.1.1* 5.13 是 8.4 2015 A.06.28
垃圾收集与基于可达性的泄漏检测 N2670 c++11
垃圾收集与基于可达性的泄漏检测(库支持) N2670 c++11 6 (无操作) 3.4 (无操作) 19.0* (无操作) N/A N/A N/A
金额、时间及十六进制浮点 I/O 操纵符 时间: N2071金额: N2072 c++11 5 3.8 19.0* N/A N/A 5.15 N/A
C++11 功能特性 提案 版本 GCC Clang MSVC EDG eccp Intel C++ IBM XLC++ Sun/Oracle C++ Embarcadero C++ Builder Cray Portland Group (PGI) HP aCC Digital Mars C++
# C++11
C++编程指南
设计模式
  • 文章目录
  • 站点概览

XuQi

44 日志
30 标签
  1. 1. C++11 & C++14 & C++17 常用新特性总结
    1. 1.1. GCC编译器(从编译器GCC4.8.X的版本完全支持)
    2. 1.2. C+11新特性
      1. 1.2.1. nullptr
      2. 1.2.2. 类型推导 auto和decltype
        1. 1.2.2.1. auto
        2. 1.2.2.2. decltype
        3. 1.2.2.3. 拖尾类型返回
      3. 1.2.3. 区间迭代
      4. 1.2.4. 初始化列表
      5. 1.2.5. 模板增强
        1. 1.2.5.1. 尖括号 “>”
      6. 1.2.6. 构造函数
        1. 1.2.6.1. 委托构造
        2. 1.2.6.2. 继承构造
      7. 1.2.7. Lambda 表达式
      8. 1.2.8. 新增容器
        1. 1.2.8.1. std::array
        2. 1.2.8.2. std::forward_list
        3. 1.2.8.3. 无序容器
        4. 1.2.8.4. 元组 std::tuple
      9. 1.2.9. 正则表达式
      10. 1.2.10. 语言级线程支持
      11. 1.2.11. 右值引用&&
        1. 1.2.11.1. std::move
        2. 1.2.11.2. 命名对象使用 std::move右值引用
        3. 1.2.11.3. 使用右值引用精确传递
        4. 1.2.11.4. 智能指针
          1. 1.2.11.4.1. shared_ptr
          2. 1.2.11.4.2. unique_ptr
          3. 1.2.11.4.3. weak_ptr
        5. 1.2.11.5. std::function
        6. 1.2.11.6. std::bind
        7. 1.2.11.7. std::forward
        8. 1.2.11.8. delete
        9. 1.2.11.9. enable_shared_from_this
          1. 1.2.11.9.1. 定义
          2. 1.2.11.9.2. 使用场合
        10. 1.2.11.10. mutable
        11. 1.2.11.11. using各种用法
      12. 1.2.12. 参考信息
    3. 1.3. C++17 功能特性
    4. 1.4. C++14 功能特性
    5. 1.5. C++11 功能特性
© 2019 XuQi
由 Hexo 强力驱动 v3.9.0
|
主题 – NexT.Muse v7.3.0