现在一些开源库里,越来越多c++17的写法了,不过c++17的支持度还不是非常广泛,但c++11已经相当普遍了。没有系统地分析c++11的新特性,在此把一些有用的写法整理整理。
typedef用起来也不错,但是理解起来确实没有using清晰:
using ItemType = pair<int, string>;
using ItemListType = vector<ItemType>;
using FuncPtr = void (*)(int);
花括号初始化列表给写代码带了很大的简洁性,而不用一个一个insert()了,结构体也不用一个一个字段赋值了:
struct Student
{
int age;
string name;
float height;
};
int main()
{
Student s1 = {24, "zhangsan", 1.78f};
auto s2 = Student{24, "zhangsan", 1.78f};
int *arr = new int[10]{1,2,3};
}
如果对于一个普通数组,我们以往遍历时这么写:
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); ++i) {
...
}
但其实这么写也是支持的:
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
for (auto it = begin(arr); it != end(arr); ++it) {
cout << *it << endl;
}
for (auto one : arr) {
cout << one << endl;
}
当然更推荐使用array来创建一个数组:
array<int, 10> arr = {1,2,3,4,5,6,7,8,9,10};
lambda配合起一些算法参数,变得非常方便,也不用传函数指针,也不用传仿函数(functor) 了。
array<int, 10> arr = {1,2,3,4,5,6,7,8,9,10};
for_each(arr.begin(), arr.end(), [](int n) { cout << n << endl; });
for_each(user_rank.begin(), user_rank.end(), [](pair<const int, string>&one) { cout << one.first << ":" << one.second << endl;});
再比如排序:
sort(arr.begin(), arr.end(), [](int x, int y) -> bool { return x >= y; });
lambda的写法格式如下:
[capture list] (params list) mutable exception-> return type { function body }
其中的捕获方式罗列如下:
捕获形式 | 说明 |
---|---|
[] | 不捕获任何外部变量 |
[变量名, …] | 默认以值得形式捕获指定的多个外部变量(用逗号分隔),如果引用捕获,需要显示声明(使用&说明符) |
[this] | 以值的形式捕获this指针 |
[=] | 以值的形式捕获所有外部变量 |
[&] | 以引用形式捕获所有外部变量 |
[=, &x] | 变量x以引用形式捕获,其余变量以传值形式捕获 |
[&, x] | 变量x以值的形式捕获,其余变量以引用形式捕获 |
关于move(),关于右值有很多可以说的,也不是很好理解。不过至少知道,move是直接交出数据所有权以减少数据拷贝,达到提升性能的目的。最最常用的例子就是,传递一个非常大的字符串string:
string description = "...";
student.description = move(description);
其实内部就是拷贝了一下string::data()指针而已。
交换两个字符串,使用move也非常合适,但直接使用std::swap()更好。千万不能当整型一样,写成auto t = s1; s1 = s2; s2 = t;
通常我们删除vector中的数组时,我们得这么写:
vector<int> arr = {1,2,3,4,5,6,7,8,9,10};
for (auto it = arr.begin(); it != arr.end();) {
if (*it < 5) {
it = arr.erase(it);
} else {
++it;
}
}
使用remove_if可以写成:
arr.erase(remove_if(arr.begin(), arr.end(), [](int n) -> bool { return n < 5; }), arr.end());
注意:remove_if并不会删除数据,只是将符合条件的移到末尾,所以还需要借助erase()来真正的删除。如果只是针对指定的某个值,可以使用常规版本remove()。remove_if不支持map/set之类的关联容器,所以对于关联容器还是得按照上面的写法进行。
在以前子类重载基类的方法时,我们都知道声明要一致。这时候因为语法要求的不严格,会导致一些问题,即子类的方法前的 virtual 可以不写,这时光看子类代码是不知道该方法是否为重载方法,而且一旦基类的方法有修改,会发现编译无问题,导致很容易忘记修改子类中重载的方法。
override就指明该方法一定是重载基类中的某函数的,final表示修饰的方法不允许子类继续重载。
class A
{
public:
virtual int add(int a, int b) {
return a + b;
}
};
class B : public A
{
public:
int add(int a, int b) override final {
return a + b + 100;
}
};
int main()
{
A *a = new B();
cout << a->add(1, 2) << endl;
return 0;
}