文章目录
- 1. 10大新特性 只是语法糖的冰山一角
- 1.1 类的委托构造函数
- 1.2 struct可以直接定义并初始化了
- 1.3 nullptr 防止类型转换 (C++建议默认使用nullptr做空代替null)
- 1.4 enum class 枚举定义和使用
- 1.5 auto 自动识别类型
- 1.6 constexpr 常量表达式, 告诉编译器编译时计算
- 1.7 map的定义和初始化, 以及遍历
- 1.8 智能指针 shared_ptr, unique_ptr, weak_ptr
- 1.9 lambda
- 1.10 emplace 容器, 构造而不是拷贝
具体可看:现代 C++ 教程:高速上手 C++ 11/14/17/20
1. 10大新特性 只是语法糖的冰山一角
1.1 类的委托构造函数
class A{
public:
A(int n){}
A() : A(10){} // 间接调用A(10)
A(int a, int b):m_a(a),m_b(b){} // 间接初始化成员变量
public:
int m_a, m_b;
};
1.2 struct可以直接定义并初始化了
struct Data{
int i=0;
float f=3.14;
bool b = true;
// Data(int i_, f_, b_): i(i_),f(f_),b(b_){} // 可以不用这样初始化
};
1.3 nullptr 防止类型转换 (C++建议默认使用nullptr做空代替null)
// 3. nullptr 防止类型转换
void func1(char *s){}
void func1(int i){}
void test1(){
// char *s = NULL; // bu合法
// int i=NULL; // bu合法
// func1(NULL); // 有歧义, 不知道调用的是哪个重写的函数
// 推荐使用下面
char *s1 = nullptr;
// int i = nullptr; // 不合法, 报错
return;
}
1.4 enum class 枚举定义和使用
enum class Number {one, two, three};
Number num = Number::one;
// int num = Number::one; // 不合法
1.5 auto 自动识别类型
auto test2(){
auto a = 1; // int 型
auto b = 3.14; // 浮点型
return a+b; // 返回的就是浮点数
}
1.6 constexpr 常量表达式, 告诉编译器编译时计算
constexpr int pow(int x, int y){
int result = x;
while(--y > 0){
result *= x;
}
return result;
}
// int a[pow(2, 10)] = {}; // 这样就在编译的时候就得到了a的数组长度
1.7 map的定义和初始化, 以及遍历
void test3(){
map<int, string> numMap = {{1, "p1"}, {2, "p2"}, {3, "p3"}};
// 新方法
for(auto &[key, value] : numMap){
cout << key << " " <<value <<endl;
}
// 老方法
for(map<int, string>::iterator it=numMap.begin(); it!=numMap.end(); it++){
cout << it->first << " " <<it->second <<endl;
}
for(auto &it: numMap){
cout << it.first << " " <<it.second <<endl;
}
}
1.8 智能指针 shared_ptr, unique_ptr, weak_ptr
- 头文件
#include <memory>
- 智能指针目的是通过栈自动回收堆空间的内存
// 智能指针 内存管理 memory
void test4(){
// unique_ptr<Data> d(new Data);
auto d = make_unique<Data>(); // 创建unique指针推荐写法, 不会出错后有野指针
d->i = 23; // 后面不需要delete d, 注意当前d不能被拷贝复制和传递给别的指针
// unique_ptr<Data> d2 = d; // 错误
// 指针在不同函数中传递, 可以使用share_ptr
auto d3 = make_shared<Data>();
auto d4 = d3;
}
1.9 lambda
C++11 新特性:Lambda 表达式
公式 | 标识 |
| (1) |
| (2) |
| (3) |
| (4) |
mutable 修饰符说明 lambda 表达式体内的代码可以修改被捕获的变量,并且可以访问被捕获对象的 non-const 方法。
exception 说明 lambda 表达式是否抛出异常(**noexcept**
),以及抛出何种异常,类似于void f() throw(X, Y)。
attribute 用来声明属性。
[] // 不捕获任何外部变量
[=] // 以值的形式捕获所有外部变量
[&] // 以引用形式捕获所有外部变量
[x, &y] // x 以传值形式捕获,y 以引用形式捕获
[=, &z] // z 以引用形式捕获,其余变量以传值形式捕获
[&, x] // x 以值的形式捕获,其余变量以引用形式捕获
另有一点需注意。对于 [=] 或 [&] 的形式,lambda 表达式可直接使用 this 指针。但对于 [] 的形式,如果要使用 this 指针,必须显式传入:[this]() { this->someFunc(); }();
struct myCompare{
bool operator()(int &x){
return x%2==0;
}
};
void test5(){
vector<int> nums = {1,4,3,2,5,6,7,8,0};
// auto it = find_if(nums.begin(), nums.end(), myCompare()); // 同下
auto it = find_if(nums.begin(), nums.end(), [](int &x){return x%2==0;});
cout << "the first odd number is " << *it <<endl;
sort(nums.begin(), nums.end(), [](int &a, int &b){return a>b;}); // 从大到小排列
// test2
std::vector<int> c { 1,2,3,4,5,6,7 };
int x = 5;
c.erase(std::remove_if(c.begin(), c.end(), [x](int n) { return n < x; } ), c.end());
for (auto i: c) {
std::cout << i << ' ';
}
std::cout << endl;
}
1.10 emplace 容器, 构造而不是拷贝
- emplace_back(构建) : 后插
- emplace_font(构建) : 前插
- emplace(location, 构建): location插
class A {
private:
string m_name;
public:
// 构造函数
A(string name): m_name(name) {cout<< "create " << m_name << " .." <<endl;}
// 拷贝构造函数
A(const A& a){
cout<< "拷贝构造函数 " <<endl;
m_name = a.m_name;
};
// 析构函数
~A(){cout<< "delete " << m_name << " .." <<endl;}
};
void test(){
vector<A> nums;
nums.reserve(10); // 先开辟10个空间再说, 不然后面如果vector不够, 会重新开辟空间,就会扰乱操作
if(nums.capacity() != 10){
cout << " 空间开辟失败" << endl;
return 0;
}
nums.push_back(A("小明")); // 构造完后, 复制到nums, 然后在销毁, 相当于这个对象构造了两次
nums.emplace_back("小王"); // 直接就是小王创建后加入到
cout << "---" <<endl;
return;
}
create 小明 ..
拷贝构造函数
delete 小明 ..
create 小王 ..
---
delete 小明 ..
delete 小王 ..