auto类型推导的语法和规则
auto 要求必须对变量进行初始化
int x = 0;
auto *p1 = &x; //p1 为 int *,auto 推导为 int
auto p2 = &x; //p2 为 int*,auto 推导为 int*
auto &r1 = x; //r1 为 int&,auto 推导为 int
auto r2 = r1; //r2 为 int,auto 推导为 int
auto与const结合
int x = 0;
const auto n = x; //n 为 const int ,auto 被推导为 int
auto f = n; //f 为 const int,auto 被推导为 int(const 属性被抛弃)
const auto &r1 = x; //r1 为 const int& 类型,auto 被推导为 int
auto &r2 = r1; //r1 为 const int& 类型,auto 被推导为 const int 类型
最后我们来简单总结一下 auto 与 const 结合的用法:
当类型不为引用时,auto 的推导结果将不保留表达式的 const 属性;
当类型为引用时,auto 的推导结果将保留表达式的 const 属性。
auto 用于泛型编程
auto 的另一个应用就是当我们不知道变量是什么类型,或者不希望指明具体类型的时候,比如泛型编程中。我们接着看例子:
#include <iostream>
using namespace std;
class A{
public:
static int get(void){
return 100;
}
};
class B{
public:
static const char* get(void){
return "http://c.biancheng.net/cplus/";
}
};
template <typename T>
void func(void){
auto val = T::get();
cout << val << endl;
}
int main(void){
func<A>();
func<B>();
return 0;
}
运行结果:
100
http://c.biancheng.net/cplus/
using定义别名(替代typedef)
C98
template <typename Val>
struct str_map
{
typedef std::map<std::string, Val> type;
};
str_map<int>::type map1;
C++11
template <typename Val>
using str_map_t = std::map<std::string, Val>;
str_map_t<int> map1;
// 重定义unsigned int
typedef unsigned int uint_t;
using uint_t = unsigned int;
// 重定义std::map
typedef std::map<std::string, int> map_int_t;
using map_int_t = std::map<std::string, int>;
C++11 tuple元组详解
struct person{
char *m_name;
char *m_addr;
int *m_ages;
};
//使用tuple来表示这样一个结构体,作用是一样的
std::tuple<const char *,const char *,int>
Lambda表达式
Lambda 表达式的 [] 用来确定捕获参数:
1.[=]:捕获的局部变量只可读不可写,捕获范围是当前 Lambda 表达式之前的作用域。
2.[&]:捕获的局部变量可读可写。
[ capture ] ( params ) opt -> ret { body; };
void MyClass::function() {
// 使用 [this] 来捕获 this
auto fun1 = [this](int v){cout << v + this->num << endl; };
// 使用 [&] 捕获所有父作用域的引用,包括 this
auto fun2 = [&](int v){cout << v + this->num << endl; };
}
int main(void) {
int num = 100;
// read only
auto fun1 = [=](){ cout << num << endl; };
fun1();
// read and write
auto fun2 = [&num](){ num = 200; cout << num << endl; };
fun2();
// num = 200
cout << num << endl;
return 0;
}
---------------------------------------------------------------------------
//遍历
int main() {
vector<int> vec = {1, 2, 3, 4, 5};
// 定义 Lambda
auto fun = [](int num){ cout << num << endl;}
for_each(vec.begin(), vec.end(), fun);
// 将 vec 中的元素都加 1,修改参数必须传递参数的引用
for_each(vec.begin(), vec.end(), [](int& num){ num += 1;});
for_each(vec.begin(), vec.end(), fun);
return 0;
}
auto f = [](int a) -> int { return a + 1; };
std::cout << f(1) << std::endl; // 输出: 2
for循环
//for循环遍历普通数组
for (char ch : arc) {
cout << ch;
}
//for循环遍历 vector 容器
for (auto ch : myvector) {
cout << ch;
}
//{}的使用
for (int num : {1, 2, 3, 4, 5}) {
cout << num << " ";
}
//for循环遍历并修改容器中各个字符的值
for (auto &ch : myvector) {
ch++;
}
右值引用
2 个 ‘&’ 表示右值引用。
int num = 10;
//int && a = num; //右值引用不能初始化为左值
int && a = 10;
某些场景中,我们可能需要限制调用成员函数的对象的类型(左值还是右值)所谓引用限定符,就是在成员函数的后面添加 “&” 或者 “&&”,从而限制调用者的类型(左值还是右值)
#include <iostream>
using namespace std;
class demo {
public:
demo(int num):num(num){}
int get_num()&{
return this->num;
}
private:
int num;
};
int main() {
demo a(10);
cout << a.get_num() << endl; // 正确
//cout << move(a).get_num() << endl; // 错误
return 0;
}
nullptr:初始化空指针
实际开发中,避免产生野指针最有效的方法,就是在定义指针的同时完成初始化操作,即便该指针的指向尚未明确,也要讲其初始化空指针。
int * a1 = nullptr;
char * a2 = nullptr;
double * a3 = nullptr;
shared_ptr智能指针
程序突然崩溃、程序运行所用内存越来越多最终不得不重启,往往都是内存资源管理不当造成。
1.有些资源已经被释放,但指向它的指针并没有改变指向(成了野指针),并且后续还在使用;
2.有些内存资源已经被释放,后期又试图在释放一次(重复释放统一内存会导致程序运行崩溃);
3.没有及时释放不在使用的内存资源,造成内存泄露,程序占用的内存资源越来越多。
std::shared_ptr<int> p1; //不传入任何实参
std::shared_ptr<int> p2(nullptr); //传入空指针 nullptr
std::shared_ptr<int> p3(new int(10));
std::shared_ptr<int> p3 = std::make_shared<int>(10);
//调用拷贝构造函数
std::shared_ptr<int> p4(p3);//或者 std::shared_ptr<int> p4 = p3;
//调用移动构造函数
std::shared_ptr<int> p5(std::move(p4)); //或者 std::shared_ptr<int> p5 = std::move(p4);
unique_ptr
unique_ptr<string> p3(new string("auto"));
unique_ptr<string> p4;
p4=p3;//此时会报错