智能指针
智能指针可以保证资源的自动释放
不带引用计数的智能指针
auto_ptr只让最后一个指向的指针管理资源,之前的auto_ptr会被置为nullptr
scoped_ptr删除了拷贝构造和赋值重载函数
unique_ptr:推荐使用,也删除了拷贝构造和赋值重载函数,但是提高了右值引用的拷贝构造和赋值重载
unique_ptr<int> ptr(new int);
unique_ptr<int> ptr2 = std::move(ptr); // 使用了右值引用的拷贝构造
ptr2 = std::move(ptr); // 使用了右值引用的operator=赋值重载函数
语义明确
带引用计数的智能指针
shared_ptr和weak_ptr标记几个在使用该指针的数量shared_ptr和weak_ptr底层的引用计数已经通过CAS操作,保证了引用计数加减的原子特性,因此shared_ptr和weak_ptr本身就是线程安全的带引用计数的智能指针。
shared_ptr:强智能指针可以改变资源的引用技术
weak_ptr:若智能指针 不会改变资源的引用技术
强智能指针的交叉引用是什么问题?什么结果?怎么解决?
#include <iostream>
#include <memory>
using namespace std;
class B; // 前置声明类B
class A
{
public:
A() { cout << "A()" << endl; }
~A() { cout << "~A()" << endl; }
shared_ptr<B> _ptrb; // 指向B对象的智能指针
};
class B
{
public:
B() { cout << "B()" << endl; }
~B() { cout << "~B()" << endl; }
shared_ptr<A> _ptra; // 指向A对象的智能指针
};
int main()
{
shared_ptr<A> ptra(new A());// ptra指向A对象,A的引用计数为1
shared_ptr<B> ptrb(new B());// ptrb指向B对象,B的引用计数为1
ptra->_ptrb = ptrb;// A对象的成员变量_ptrb也指向B对象,B的引用计数为2
ptrb->_ptra = ptra;// B对象的成员变量_ptra也指向A对象,A的引用计数为2
cout << ptra.use_count() << endl; // 打印A的引用计数结果:2
cout << ptrb.use_count() << endl; // 打印B的引用计数结果:2
/*
出main函数作用域,ptra和ptrb两个局部对象析构,分别给A对象和
B对象的引用计数从2减到1,达不到释放A和B的条件(释放的条件是
A和B的引用计数为0),因此造成两个new出来的A和B对象无法释放,
导致内存泄露,这个问题就是“强智能指针的交叉引用(循环引用)问题”
*/
return 0;
}
代码打印结果:
A()
B()
2
2
可以看到,A和B对象并没有进行析构,通过上面的代码示例,能够看出来“交叉引用”的问题所在,就是对象无法析构,资源无法释放,那怎么解决这个问题呢?请注意强弱智能指针的一个重要应用规则:定义对象时,用强智能指针shared_ptr,在其它地方引用对象时,使用弱智能指针weak_ptr。
弱智能指针weak_ptr区别于shared_ptr之处在于:
- weak_ptr不会改变资源的引用计数,只是一个观察者的角色,通过观察shared_ptr来判定资源是否存在
- weak_ptr持有的引用计数,不是资源的引用计数,而是同一个资源的观察者的计数
- weak_ptr没有提供常用的指针操作,无法直接访问资源,需要先通过lock方法提升为shared_ptr强智能指针,才能访问资源
那么上面的代码怎么修改,也就是如何解决带引用计数的智能指针的交叉引用问题,代码如下:
#include <iostream>
#include <memory>
using namespace std;
class B; // 前置声明类B
class A
{
public:
A() { cout << "A()" << endl; }
~A() { cout << "~A()" << endl; }
weak_ptr<B> _ptrb; // 指向B对象的弱智能指针。引用对象时,用弱智能指针
};
class B
{
public:
B() { cout << "B()" << endl; }
~B() { cout << "~B()" << endl; }
weak_ptr<A> _ptra; // 指向A对象的弱智能指针。引用对象时,用弱智能指针
};
int main()
{
// 定义对象时,用强智能指针
shared_ptr<A> ptra(new A());// ptra指向A对象,A的引用计数为1
shared_ptr<B> ptrb(new B());// ptrb指向B对象,B的引用计数为1
// A对象的成员变量_ptrb也指向B对象,B的引用计数为1,因为是弱智能指针,引用计数没有改变
ptra->_ptrb = ptrb;
// B对象的成员变量_ptra也指向A对象,A的引用计数为1,因为是弱智能指针,引用计数没有改变
ptrb->_ptra = ptra;
cout << ptra.use_count() << endl; // 打印结果:1
cout << ptrb.use_count() << endl; // 打印结果:1
/*
出main函数作用域,ptra和ptrb两个局部对象析构,分别给A对象和
B对象的引用计数从1减到0,达到释放A和B的条件,因此new出来的A和B对象
被析构掉,解决了“强智能指针的交叉引用(循环引用)问题”
*/
return 0;
}
绑定器和函数对象
bind1st:operator()中第一个形参变量绑定成一个确定的值
bind2st:operator()中第二个形参变量绑定成一个确定的值
绑定器+二元函数对象->一元函数对象
auto it1 = find_if(vec.begin(),vec.end(),
bind1st(greater<int>(),70);) //find_if寻找第一个小于70
void hello1(){
cout << "hello world!"<< endl;
}
function<void> func1 = hello1;
func1();//"hello world!"
function<int(int,int)> func2 = [](int a,int b)->int {return a+b};
function
std::function还有一个特别有意思的用法,你可以将一个重载了()操作符的对象赋值给它,这样就可以像调用函数一样使用该对象了。
...
struct A {
void operator()() {
std::cout << "This is A Object" << std::endl;
}
};
...
int main(...){
...
A a;
func = a;
func();
...
}
模板的完全特例化:所有参数都标记上
模板的部分特例化:例如只表明是指针,没表明是哪种类型的指针
bind绑定器,绑定参数
void hello ( string str) { cout << str << endl; }
int sum ( int a, int b){ return a + b; }
bind (hello, "hello bind ! ")();
cout <<bind (sum, 10,20)() <<endl;
//参数占位符绑定器出了语句,无法继续使用
bind (hello,_1) ( "hello bind 2 ! " );
cout << bind (sum,_1,_2) (200,300 )<<endl;
//此处把bind返回的绑定器binder就复用起来了
function<void(string) > func1 = bind (hello,_1);
func1 ( "hello china ! " ) ;
func1 ( "hello shan xi ! " );
func1 ( "hello si chuan ! " );
lambda表达式
lambada表达式的语法
//[捕获外部变量](形参列表)->返回值{操作代码};
auto func1 = []()->void {cout << "hello world!" << endl;};
如果不需要返回值那么->void可以省略
->可以省略(1):如果function body中存在return语句,则该Lambda表达式的返回类型由return语句的返回类型确定; (2):如果function body中没有return语句,则返回值为void类型。
捕获外部变量
[]不捕获任何外部变量
[=]传值捕获
[&]传引用捕获
[this]捕获外部的this指针
[=,&a]引用捕获a其余传值捕获
int a = 10;
int b = 20;
auto func3 = [&a,&b]()
{ int tmp = a;
a = b
b = tmp;
};
func3(); //a=20 b=10
lambada表达式->函数对象function
map<int,function<int(int,int)>> caculateMap;
caculateMap[1] = [](int a, int b)->int{return a + b;};
caculateMap[2] = [](int a, int b)->int{return a - b;};
caculateMap[3] = [](int a, int b)->int{return a * b;};
caculateMap[4] = [](int a, int b)->int{return a / b;};
修改捕获变量
前在Lambda表达式中,如果以传值方式捕获外部变量,则函数体中不能修改该外部变量,否则会引发编译错误。那么有没有办法可以修改值捕获的外部变量呢?这是就需要使用mutable关键字,该关键字用以说明表达式体内的代码可以修改值捕获的变量,示例:
int a = 123;
auto f = [a]()mutable { cout << ++a; }; // 不会报错 输出124
标签:int,绑定,C++,计数,对象,引用,lambda,ptr,指针
From: https://www.cnblogs.com/KongJiBlogs/p/17265137.html