c++ 智能指针笔记

#include <iostream>
#include <string>
#include <memory>

//智能指针的测试
class Student
{

public:
	Student() {};
	Student(int id, int grades, std::string name) :ID(id), Grades(grades), Name(name) {};
	~Student() {};
	int ID;
	int Grades;
	std::string Name;

public:
	void SetStudent(int id,int grades, std::string name)
	{
		this->ID = id;
		this->Grades = grades;
		this->Name = name;
	}
	void PrintStudent()
	{
		std::cout << this->ID << " " << this->Grades << " " << this->Name << std::endl;
	}
};

/*
///参考链接
https://blog.csdn.net/hp_cpp/article/details/103452196
https://blog.csdn.net/qq_41543888/article/details/90269614
https://blog.csdn.net/baidu_41388533/article/details/106559310

*/

void Delete(Student* s)
{
	delete[] s;
}
int main()
{	
	Student student0(0,90,"nity");
	student0.PrintStudent();


	//智能指针的方式(构造单个对象)
	std::shared_ptr<Student> student1(new Student(1,91,"nity_noe"), [](Student*s){delete s; });
	//lamba表达式删除
	std::shared_ptr<Student> student2(new Student[5], [](Student*s) {delete[] s;});
	//默认删除
	std::shared_ptr<Student> student3(new Student[5], std::default_delete<Student[]>());
	//函数删除
	std::shared_ptr<Student> student4(new Student[5], Delete);

	//构造单个对象,无参构造
	std::shared_ptr<Student> student5(new Student(), [](Student*s) {delete s;});
	

	std::shared_ptr<Student> student6(new Student, std::default_delete<Student>());
	//student1->PrintStudent();
	std::weak_ptr<Student> p(student1);
	//引用计数
	std::cout<<p.use_count()<<std::endl;

	//二维指针数组
	//参考 https://segmentfault.com/q/1010000008242849?sort=created
	//参考 https://blog.csdn.net/goldenhawking/article/details/78162094
	//二维数组第一维是动态的,第二维是静态的
	std::shared_ptr<Student[1024][10]> pt(new Student[1024][10], [=](Student(*p)[10])->void {delete[] p; });

	pt[1023][20].ID = 5;
	student5->ID = 5;
	student5->Grades = 95;
	student5->Name = "nity_five";
	student5->PrintStudent();
	system("pause");
	return 0;
}


注意事项:

1、unique_ptr的数组智能指针,没有*->操作,但支持下标操作[]
2、shared_ptr的数组智能指针,有*->操作,但不支持下标操作[],只能通过get()去访问数组的元素。
3、shared_ptr的数组智能指针,必须要自定义deleter,定义可以参考上面的内容。
 参考链接
 https://blog.csdn.net/weixin_30929195/article/details/98524505

unique_str的使用与初始化。
std::unique_ptr<int[]> pnColhistT(new int[nCol] {0});
std::unique_ptr<int[]> pnRowhist(new int[nRow] {0});
其他的初始化方法:
//方法1
std::unique_ptr<int[]> ptr1{ new int[5]{1,2,3,4,5} };
//方法2
auto ptr2 = std::make_unique<std::array<int, 5>>(std::array<int, 5>{1, 2, 3, 4, 5});
//方法3,但还是建议使用vector来表示数组
shared_ptr<vector<int>> ptr3 = make_shared<vector<int>>();

4、lambda表达式

lambda表达式的语法归纳如下:

[ caputrue ] ( params ) opt -> ret { body; };

1).capture是捕获列表;

2).params是参数表;(选填)

3).opt是函数选项;可以填mutable,exception,attribute(选填)

mutable说明lambda表达式体内的代码可以修改被捕获的变量,并且可以访问被捕获的对象的non-const方法。

exception说明lambda表达式是否抛出异常以及何种异常。

attribute用来声明属性。

4).ret是返回值类型。(选填)

5).body是函数体。

捕获列表:lambda表达式的捕获列表精细控制了lambda表达式能够访问的外部变量,以及如何访问这些变量。

1).[]不捕获任何变量。

2).[&]捕获外部作用域中所有变量,并作为引用在函数体中使用(按引用捕获)。

3).[=]捕获外部作用域中所有变量,并作为副本在函数体中使用(按值捕获)。

4).[=,&foo]按值捕获外部作用域中所有变量,并按引用捕获foo变量。

5).[bar]按值捕获bar变量,同时不捕获其他变量。

6).[this]捕获当前类中的this指针,让lambda表达式拥有和当前类成员函数同样的访问权限。如果已经使用了&或者=,就默认添加此选项。捕获this的目的是可以在lamda中使用当前类的成员函数和成员变量。

 class A
 {
 public:
     int i_ = 0;
     
     void func(int x,int y){
         auto x1 = [] { return i_; };                             //error,没有捕获外部变量
         auto x2 = [=] { return i_ + x + y; };               //OK
         auto x3 = [&] { return i_ + x + y; };               //OK
         auto x4 = [this] { return i_; };                        //OK
         auto x5 = [this] { return i_ + x + y; };            //error,没有捕获x,y
         auto x6 = [this, x, y] { return i_ + x + y; };    //OK
         auto x7 = [this] { return i_++; };                   //OK
 };
 
 int a=0 , b=1;
 auto f1 = [] { return a; };                            //error,没有捕获外部变量    
 auto f2 = [&] { return a++ };                      //OK
 auto f3 = [=] { return a; };                         //OK
 auto f4 = [=] {return a++; };                     //error,a是以复制方式捕获的,无法修改
 auto f5 = [a] { return a+b; };                     //error,没有捕获变量b
 auto f6 = [a, &b] { return a + (b++); };      //OK
 auto f7 = [=, &b] { return a + (b++); };     //OK



注意的细节:

一个容易出错的细节是lambda表达式的延迟调用,lambda表达式按值捕获了所有外部变量。在捕获的一瞬间,a的值就已经被复制了。如果希望lambda表达式在调用时能即时访问外部变量,我们应当使用引用方式捕获。

 int a = 0;
 auto f = [=] { return a; };
 
 a+=1;
 
 cout << f() << endl;       //输出0
 
 
 int a = 0;
 auto f = [&a] { return a; };
 
 a+=1;
 
 cout << f() <<endl;       //输出1

虽然按值捕获的变量值均补复制一份存储在lambda表达式变量中, 修改他们也并不会真正影响到外部,但我们却仍然无法修改它们。

那么如果希望去修改按值捕获的外部变量,需要显示指明lambda表达式为mutable。

需要注意:被mutable修饰的lambda表达式就算没有参数也要写明参数列表。
  原因:lambda表达式可以说是就地定义仿函数闭包的“语法糖”。它的捕获列表捕获住的任何外部变量,最终均会变为闭包类型的成员变量。按照C++标准,lambda表达式的operator()默认是const的,一个const成员函数是无法修改成员变量的值的。而mutable的作用,就在于取消operator()的const。

int a = 0;
auto f1 = [=] { return a++; };                       //error
auto f2 = [=] () mutable { return a++; };       //OK

没有捕获变量的lambda表达式可以直接转换为函数指针,而捕获变量的lambda表达式则不能转换为函数指针。原因可以参考2中的原因。

typedef void(*Ptr)(int*);
 
Ptr p = [](int* p) { delete p; };              //OK
Ptr p1 = [&] (int* p) { delete p; };         //error

最后,两个实际应用到lambda表达式的代码。

std::vector<int> v = { 1, 2, 3, 4, 5, 6 };
int even_count = 0;
for_each(v.begin(), v.end(), [&even_count](int val){
    if(!(val & 1)){
        ++ even_count;
    }
});
std::cout << "The number of even is " << even_count << std::endl;




**********************************
int count = std::count_if( coll.begin(), coll.end(), [](int x){ return x > 10; });
 
int count = std::count_if( coll.begin(), coll.end(), [](int x){ return x < 10; });
 
int count = std::count_if( coll.begin(), coll.end(), [](int x){ return x > 5 && x<10; });


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值