C++ 动态内存
new 和 delete
常规变量存储在被称为 栈 的内存区域中,而
new 从被称为 堆 或
自由存储区 的内存区域中分配内存
new 分配的内存使用 delete 释放,已经释放的内存不能再用 delete
释放,new 和 delete 成对出现,尽量放在一个函数中
new 分配的内存都是动态分配的,不是在编译时分配
运算符 new 和 new[] 分别调用如下函数:
12void * operator new (std::size_t); // used by newvoid * operator new[] (std::size_t); // used by new[]
这些函数被称作分配函数,位于全局名称空间,同样也有
delete 和 delete[] 调用的释放函数
12345678int *p = new int[3];p[0] = 0;p[1] = 1;p[2] = 2;cout << p[0] << endl; // 0p = p + 1;cout << p[0] << endl; // 1 delete [] p; ...
C++ 智能指针
智能指针
C++ 11
提供了两种智能指针,区别在于管理底层指针的方式,shared_ptr
允许多个指针指向一个对象,unique_ptr
则独占所指向的对象。另外还定义了一个伴随类
weak_ptr,是一种弱引用,指向
shared_ptr 所管理的对象。
循环引用问题
shared_ptr 对象离开作用域后,其内部的引用计数器将减
1,若引用计数器为 0,则会自动释放内存
循环引用指两个对象互相使用其内部的 shared_ptr
指向对方,造成内存泄漏。
123456789101112131415161718192021222324252627282930313233343536373839#include <iostream> #include <memory> using namespace std; class B;class A { public: shared_ptr<B> a; ~A() { cout << "delete class A" << en ...
C++ lambda
lambda 介绍
lambda 表达形式
1[capture list](parameter list) -> return type { function body }
cpature list 是一个 lambda 所在函数定义中的局部变量的列表
return type,parameter list 和 function body 与普通函数一样
与普通函数不同的是,lmbda必须使用尾置返回
lambda 可以忽略参数列表和返回类型,但必须永远包含捕获列表和函数体
12auto f = [] {return 42;};cout << f() << endl;
传递参数
以 vector 排序为例
12vector<int> v{2,1,3}; sort(v.begin(), v.end(), [](const int& a, const int& b){return a < b;});
lambda 不能有默认参数
捕获列表
lambda 如果想使用函数内的局部变量,需要去捕获
捕获列表
解释
...
C++ constexpr
constexpr
当使用 constexpr 声明一个对象或函数时,意味着它的值或结果可以在编译时计算,而不是在运行时。这允许进行性能优化,并使得常量可以在需要编译时值的上下文中使用。
123constexpr int mf = 20; // 20 is a constant expressionconstexpr int limit = mf + 1; // mf + 1 is a constant expressionconstexpr int sz = size(); // ok only if size is a constexpr function
constexpr 对象和函数隐式地是 const 的
constexpr 函数
constexpr
函数必须有返回值,返回类型必须是字面类型(算术类型,引用,指针等)
1constexpr size_t scale(size_t cnt) { return new_sz() * cnt; }
假如 scale 函数传入的是 const
类型,那么返回的就是 const 表达式,否则就不是
1234// 举个例子int valu ...
C++ 后置返回类型
后置返回类型
C++11 新特性
当需要返回值时,我们没法判断 函数模版 需要返回什么类型
1234567template<typename T1, typename T2>?type? gt(T1 x, T2 y){ ... return x + y; ...}
decltype
不能直接解决这种情况,所以 C++11 提出了后置返回类型
123double h(int x, float y);auto h(int x, float y) -> double;
将返回类型移到参数声明后面,->double
被称为后置返回类型
1234567template<typename T1, typename T2>auto gt(T1 x, T2 y) -> decltype(x + y){ ... return x + y; ...}
使用后置返回类型就解决了该问题
函数返回数组
1auto func(int i) -> int(*)[10];
C++ decltype
decltype
C++11 关键字
decltype,decltype(expression)
decltype 可以用于获取变量或表达式的类型
12int x = 0;decltype(x) y = 1;
除此之外,在 函数模版 中有很大的作用
1234567template<typename T1, typename T2>void ft(T1 x, T2 y){ ... ?type? xpy = x + y; ...}
这种情况我们无法判断 x+y 需要返回什么类型,使用
decltype 就能够解决这个问题
1234567template<typename T1, typename T2>void ft(T1 x, T2 y){ ... decltype(x + y) xpy = x + y; ...}
特殊例子
12double x = 4.4;decltype((x)) r = x; // r is double &
此时 expression 为 (x),所以 r 的类型是
double 类型的引用
函 ...
C++ 函数模版
函数模版
使用 泛型
定义函数,通常把模板放在头文件中
在标准 C++98 添加关键字 typename 之前,是使用关键字 class
来创建模板
1234567891011template <typename AnyType> // 许多程序员将 AnyType 简写成 T// template <class AnyType>void Swap(AnyType &a, AnyType &b);void Swap(AnyType &a, AnyType &b){ AnyType temp; temp = a; a = b; b = temp;}
如果是数组,上面写法就不成立
12345678910111213template <typename T>void Swap(T a[], T b[], int n);void Swap(T a[], T b[], int n){ T temp; for (int i = 0; i < n; i++) { temp ...