EagleBear2002 的博客

这里必须根绝一切犹豫,这里任何怯懦都无济于事

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

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 值。

    左值 右值
    非 const 引用 可绑定 不可绑定
    const 引用 可绑定 可绑定
    右值引用 不可绑定 可绑定
  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
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++中使用移动构造函数
}

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
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 的内容
}

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);
}

常量表达式

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

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
27
28
29
30
31
32
33
34
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();

Ex2 常量对象

  1. 所有评估都可以在编译时完成。 因此,提高了运行时间效率。
  2. 编译时确定的
1
2
3
4
5
6
7
8
9
10
11
12
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
}

Lambda Function

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

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
27
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; });

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;
});
}

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

Delegating Constructor

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
#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) ?

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};

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)