2020-C++高级程序设计-C++ 11

C++ 11

  1. R-value Reference and Move Constructor
  2. Extern Templates
  3. Constant Expressions
  4. Lambda Function
  5. Delegating Constructor
  6. Uniform Initialization
  7. nullptr

1. R-value Reference - 1

  1. L-values: 具有可通过编程方式访问正在运行的程序的存储地址。
  2. a = 1 + 2
1
2
3
4
class A{};
int main() {
A a = A();//r-value
}
  1. 在C++中,非const引用可以绑定到左值,而const引用可以绑定到左值和右值,但是没有什么可以绑定到非const r值。
  2. 右值不可以绑定非常量引用,避免临时变量的修改造成的问题
1
2
3
4
5
6
7
8
9
10
class A{};
A getA(){
return A();//右值
}
int main() {
int a = 1;
int &ra = a; //OK
const A &ca = getA();//OK
A &aa = getA();//ERROR,右值不能给左值引用
}
  1. 右值引用只能绑定在右值上
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class A{
int val;
void setVal(int v) {
val = v;
}
};
A getA(){
return A();
}
//知道风险,并且想要改变新对象,就是右值引用&&
int main() {
int a = 1;
int &ra = a; //OK
const A &cra = getA();//OK
A &&aa = getA();//OK
aa.setVal(2);//OK
//…
}

1.1. 利用右值构建移动构造函数

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
class MyArray {
int size;
int *arr;
public:
MyArray():size(0),arr(NULL){}
MyArray(int sz):
size(sz),arr(new int[sz]) {
//init array here…
}
MyArray(const MyArray &other):
size(other.size),
arr(new int[other.size]) {
for (int i = 0; i < size; i++) { arr[i] = other.arr[i];
}
}
//main函数中第三种声明方式的移动构造
MyArray (MyArray &&other):
size(other.size), arr(other.arr) {
other.arr = NULL;
}
~ MyArray() {
delete[] arr;
}
}
MyArray change_aw(const MyArray &other)
{
MyArray aw(other.get_size());
//Do some change to aw.
//….
return aw;
}

int main() {
MyArray myArr(5);
MyArray myArr2 = change_aw(myArr);//调用了两次拷贝,先将myArr传入的时候进行一次拷贝,返回之后再次进行拷贝,比较大的开销
MyArray &&myArr2 = change_aw(myArr);//右值函数,直接用移动构造函数,右值引用造成的维护困难
MyArray myArr2 = change_aw(myArr);//有了新的移动构造函数,自动适配,15min,提高拷贝速度在C++中使用移动构造函数
}

1.2. Move assignment 拷贝赋值

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
class MyArray {
public:
//…
MyArray &operator=(const
MyArray &other) {
if (this == &other)
return *this;
if (arr) { delete[] arr; arr = NULL;
}
size = other.size;
memcpy(arr, other.arr, size * sizeof(int));
return *this;
}
MyArray &operator=(ArrayWrapper
&&other) {
size = other.size;
arr = other.arr;
other.arr = NULL;
return *this;
}
}
int main() {
MyArray myArr;
myArr = MyArr(5);//MyArr是临时对象,19min的内容
}

2. Extern Templates

  1. Avoid of unnecessary instantiation.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//myfunc.h
template<typename T>
void myfunc(T t){}

//test.cpp
#include "myfunc.h"
int foo(int a){
myfunc(1);
return 1;
}
//main.cpp
#include "myfunc.h"
//如果没有以下的模板,那么编译器会先去实例化模板,新的方式外部模板可以避免多次实例化的问题
/*Tell compiler: this instance has been
instantiated in another module!*/
extern template void myfunc<int>(int);

int main() {
myfunc(1);
}

3. 常量表达式

  1. 提供了更一般的常量表达式
  2. 允许常量表达式使用用户自定义类型
  3. 提供一种方法来确保在编译时完成初始化
  4. 必须在编译的时候可以确定常量表达式

3.1. Ex1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
enum Flags { GOOD=0, FAIL=1, BAD=2, EOF=3 };
constexpr int operator| (Flags f1, Flags f2) {
return Flags(int(f1)|int(f2));
}//如果不加constexpr则结果被认为是变量不能使用在case中
void f(Flags x) {
switch (x) {
case BAD: /* ... */break;
case EOF: /* ... */ break;
case BAD|EOF: /* ... */ break;//OK,必须是简单的确认的值
default: /* ... */ break;
}
}
void f(Flags x) {
switch (x) {
case bad_c(): /* ... */break;
case eof_c(): /* ... */ break;
case be_c(): /* ... */ break;
default: /* ... */ break;
}
}
constexpr int bad_c();
constexpr int eof_c();
constexpr int be_c();

3.2. Ex2 常量对象

  1. 所有评估都可以在编译时完成。 因此,提高了运行时间效率。
  2. 编译时确定的
1
2
3
4
5
6
7
8
9
10
11
struct Point {
int x,y;
constexpr Point(int xx, int yy) : x(xx), y(yy) { }
};
int main() {
constexpr Point origo(0,0);//完全常量,在常量表上
constexpr int z = origo.x;

constexpr Point a[] = {Point(0,0), Point(1,1), Point(2,2) };
constexpr int x = a[1].x; // x becomes 1
}

4. Lambda Function

  1. Also names as Lambda Expression.
  2. A mechanism for specifying a function object

4.1. Ex1

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
bool cmpInt(int a, int b) {return a < b;}
class CmpInt {
bool operator()(const int a, const int b) const {
return a < b;
}
};
int main() {
std::vector<int> items { 4, 3, 1, 2 };
std::sort(items.begin(), items.end(), cmpInt); //Function Pointer
std::sort(items.begin(), items.end(), CmpInt()); //Function Object (Functor)
std::sort(items.begin(), items.end(),
[](int a, int b) { return a < b; } //Lambda Function
);
return 0;
}
template <class RandomAccessIterator, class Compare>
void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp) {
//…
if ( comp(*it1, *it2) )
//…
}
//std::function 是C++对所有可调用的函数的封装
std::function<bool(int, int)> f1(cmpInt);
std::function<bool(int, int)> f2(CmpInt);
std::function<bool(int, int)> f3([](int a, int b) { return a < b;} );

4.2. Ex2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
vector<string> str_filter(vector<string> &vec, function<bool(string &)> matched){
vector<string> result;
for (string tmp : vec) {
if (matched(tmp))
result.push_back(tmp);
}
return result;
}
//可以会用局部变量,40min
int main(){
vector<string> vec = {"www.baidu.com", "www.kernel.org", "www.google.com"};
string pattern = ".com";
vector<string> filterd = str_filter(vec,
[&](string &str) {
if (str.find(pattern) != string::npos)
return true;
return false;
});
}

4.3. Lambda capture

符号 含义
[] Capture nothing
[&] Capture any referenced variable by reference
[=] Capture any referenced variable by making a copy
[=, &foo] Capture any referenced variable by making a copy, but capture variable foo by reference
[bar] Capture bar by making a copy; don’t copy anything else

5. Delegating Constructor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#define MAX 256
class X {
int a;
void validate(int x) { if (0<x && x<=MAX) a=x; else throw bad_X(x); }
public:
X(int x) { validate(x); }
X() { validate(42); }
// ...
};
class X {
int a;
public:
X(int x) { if (0<x && x<=max) a=x; else throw bad_X(x); }
X() :X(42) { }
// ...
};
X(int x = 42) ?

6. Uniform Initialization

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
//Old style initialization
vector<int> vec;
vec.push_back(1);
//…
//New style initialization
vector<int> vec = {1, 2, 3};
//Compiler will translate {} as initializer_list<int> 新的初始化表
template class vector<T> {
//..
vector(initializer_list<T> list) {
for (auto it = list.begin(); it != list.end(); ++it)
push_back(*it);
}
};
int arr[] = {1, 2, 3}; //OK
vector<int> vec = {1, 2, 3};
A a= {1, 2, 3};

class A{
int x, y, z;
//Default generated by compiler
A(initializer_list<int> list) {
auto it = list.begin();
x = *it++;
y = *it++;
z = *it;
}
};
//Uniform Initialization achieved!
int arr[] = {1, 2, 3};
vector<int> vec = {1, 2, 3};
A a = {1, 2, 3};

7. nullptr

1
2
3
4
5
6
7
void f(int);//f(0)
void f(char*);

f(0); // call f(int)
f(nullptr); // call f(char*)

f(NULL);// call f(int)

2020-C++高级程序设计-C++ 11
https://spricoder.github.io/2020/07/01/2020-C-plus-plus-advanced-programming/2020-C-plus-plus-advanced-programming-C++%2011/
作者
SpriCoder
发布于
2020年7月1日
许可协议