C++11 智能指针
智能指针实质
实质:一个模板类(在堆上),只有一个成员----即传送进来的原始指针。
头文件#include<memory>
独占智能指针
该指针所指向的地址只能由此指针去访问,不能指针值传递,也不能拷贝构造。
int *p=new int;
*p=2;
unique_ptr<int>h(p); //独占智能指针h, 原始指针p
//*h与*p所指地址一致。
unique_ptr<int>k(new int);
*h.get(); //获得原始指针,暂时获得,原智能指针不变
*h.release(); //获得原始指针,并将原来的智能指针置空
unique_ptr<int>h1; ~~h1=h;~~
//这是错误的,独占智能指针不能值传递
h.reset(); //释放掉指针所占资源
h.reset(new int(3)); //释放掉指针所占资源,
//并重新申请资源,并赋值为3
h=nullptr; //h置空,自动释放掉之前new的空间
int *p= new int[2]; //普通的指针数组
unique_ptr<int[]>p2(new int[2]); //独占智能指针数组
共享智能指针
多个指针可以指向同一个地址,其内部有计数(k2.use_count();
)-----表示当前资源被多少指针引用,当计数为0时;自动释放此资源。
shared_ptr<int>K2(new int(20));
make_shared<指针类型>指针变量名(所指地址中存放的内容)
<----->shared_ptr<类型>指针变量名(new 类型(内容))
//指向一个值为10个9的string类型的shared_ptr
shared_ptr<string> p1 = make_shared<string>(10, '9');
//指向一个值为42的int类型的shared_ptr
shared_ptr<int> p2 = std::make_shared<int>(42);
弱智能指针
可以将共享指针或弱指针赋值给它,同时共享指针计数不会加一(解耦),弱指针与原来给它赋值的指针无联系。
weak_ptr<int>k1 = k3; //k3为一个shared_ptr智能指针,且此时k3计数并未加一
//使用弱智能指针前要判断该弱智能指针所指的资源是否过期
//(过期返回true)
if(k1.expired()==true)
{
cout<<"k3已过期"<<endl;
}
k0.lock();//返回共享指针,若共享指针已过期;
//则返回空的共享指针
智能指针删除器
自定义智能指针的释放
shared_ptr<int>k3(new int(15),delet);
//自定义的void delet()函数来删除智能指针
shared_ptr<int,void(*)(int *)>k4(new int(100),delet);
//自定义的void delet(int *)函数来删除智能指针
//以上对unique_ptr同样适用
C++11强制转换
const_cast(去常量化)
const_cast用于强制去掉不能被修改的常数特性,其去除常量性的对象一般为指针或引用。
const_cast<强制转换的目标类型>(变量名)
该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, 强制转换的目标类型和变量的类型必须要一样。
static_cast(静态转换)
static_cast<强制转换的目标类型>(变量名)
该运算符用于数据丢失转换(高字节类型向低字节类型转换),基本数据类型之间的转换,不能对常量,指针进行强制转换,空指针(void*)除外。
dynamic_cast (动态转换)
dynamic_cast<强制转换的目标类型>(变量名)
该运算符只能用于类间转换,支持类间交叉转换,不能操作普通数据。
该运算符可以用来:
- 将派生类的指针或引用转换成基类的指针或引用。
- 在基类存在虚函数的前提下(即父类子类间存在多态),将基类的指针或引用转换成派生类的指针或引用
reinterpret_cast
reinterpret_cast<强制转换的目标类型>(变量名)
该运算符主要有几种强制转换用途:将指针或引用转换为一个足够长度的整型、将整型转换为指针或引用类型。
C++11可变参数模板
template<class……A> //……A是一个模板参数包
//(包含0---n个不同类型的参数)
void function(A……arg) //arg是一个函数参数包
{
cout<<sizeof……(arg)<<endl; //打印出参数包中参数的个数
}
//……在参数左侧,代表一个可变参数,
//……在一个参数右侧代表一个函数包的展开
//(即一组可能相同,也可能不同的实参)
//非递归方式取出所有参数
template<typename... Args>
void print(const Args&... args)
{
int dummy[] = {(std::cout << args << std::endl, 0)...};
//匿名函数与变长数组
}
//以递归方式取出所有参数
void print(){}
template<typename T, typename ……T1>
void print(T& a, T1& ……b)
{
cout<<a<<endl;
print(b……); //参数包展开
}
省略符形参
省略符形参只能写在形参列表的最后一个位置。
void fun(……);
void fun(int i,……);
//当判断参数中第一个参数是整数,就会执行fun(int i,……);
//否则无论有好多参数,无论什么类型,只有不满足条件,都会执行fun(……);
bind绑定函数
头文件#include<functional>
例子:
#include<iostream>
#include<functional>
using namespace std;
void fun1(int a, int b)
{
cout<<a<<b<<endl;
}
auto f1=std::bind(fun1,10,20); //绑定函数
auto f2=std::bind(fun1,_1,_2);
//_1,_2 ……是占位符,表示该位置参数未被绑定,
//_1代表该位置参数由传入的第一个参数决定
int main()
{
f1(); //等同于fun1(10,20);
f2(40,50); //等同于fun1(40,50);
//f2的类型为std::function<void(int,int)>
return 0;
}
bind 绑定类成员函数:
std::bind(&类名::函数名,&对象名,参数1,参数2……);
- 第一个参数是类成员函数地址
- 第二个参数是对象地址
- 该成员函数的参数……
C++11 function(函数指针的衍生物)
针对不同的可调用类型进行单独声明,则函数参数只能接收某种具体类型,这非常的不灵活,所以需要使用一种统一的方式保存可调用对象或者传递可调用对象(即函数),于是就有了std::function。
简单来说,bind可以将函数变成一个"变量",function可以将这个"变量"存起来。
std::function<函数返回值类型(函数参数各个类型)> 变量名;
上面bind的绑定函数后的变量类型就是function
例子:
void fun1(int a, int b)
{
cout<<a<<b<<endl;
}
std::function<void(int, int)> fn = fun1;
int main()
{
fn(20,30);
return 0;
}
//通常与bind绑定一起使用
std::function<void(int, int)> fn = std::bind(fun1,10,20);
// 这样 想要调用fun1(10,20);就可以直接调用fn();
//以上还有一种更通用的写法:
std::function<decltype(fun1(10,20))()> fn
= std::bind(fun1,10,20);
//被bind绑定后,可以近似的将新的函数-----即fn()看作无参函数
C++11 匿名函数
[](参数1,参数2,……){} //匿名函数形式
[] 未定义变量,即在这个函数内使用任何外部变量都是错误的
[x,&y] 外部变量x,按值传递进入此函数,y按引用进入此函数(可以使用这两个外部函数)
[&] 可以使用外部变量,且所有外部变量都是按照引用进入此函数
[=] 可以使用外部变量,且所有外部变量都是按照值传递进入此函数
[&,x] x按照值传递进入此函数,其余外部变量按引用进入此函数
例子:
auto fun=[](int a){cout<<a<<endl;}
fun(3); 此时fun相当于函数指针