#include
#include // 智能指针的头文件引入
using namespace std;
class Person{
public:
~Person(){
cout << "Person 析构函数" << endl;}
};
int mian(){
Person * person1 = new Person();//堆区开辟
//以前 delete person1;
// 现在:
shared_ptr<Person> sharedPtr1(person1);// 智能指针帮你释放堆区开辟的--》Person析构函数
Person * person2 = new Person();
//sharedPtr2 是在栈区开辟的,每添加一个元素 +1 引用计数
shared_ptr<Person> sharedPtr2(person2);
return 0;
}//main函数弹栈会释放所有的栈成员, sharedPtr1 sharedPtr2 执行对应的析构函数-1
智能指针有循环依赖的问题,要用就用好,不要用的复杂。
#include
#include // 智能指针的头文件引入
using namespace std;
// 先声明,让Person1能直接找到Person2,他们相互拥有,函数只能找到在自己之前声明的函数
class Person2;
class Person1{
public:
shared_ptr<Person2> person2;
~Person1(){
cout << "Person1 析构函数" << endl;}
};
class Person2{
public:
shared_ptr<Person1> person1;
~Person2(){
cout << "Person2 析构函数" << endl;}
};
int mian(){
Person1 * person1 = new Person1();
Person2 * person2 = new Person2();
shared_ptr<Person> sharedPtr1(person1); // + 1 计数
shared_ptr<Person> sharedPtr2(person2);// + 1 计数
cout << "前 sharedPtr1计数是:" << sharedPtr1.use_conut() << endl;
cout << "后 sharedPtr2计数是:" << sharedPtr2.use_conut() << endl;
// 循环依赖 强引用导致泄露,使用weak_ptr person2则不会出现该问题
person1->person2 = sharedPtr2;
person2->person1 = sharedPtr1;
// 计数变成2
cout << "前 sharedPtr1计数是:" << sharedPtr1.use_conut() << endl;
cout << "后 sharedPtr2计数是:" << sharedPtr2.use_conut() << endl;
return 0;
}//main函数弹栈会释放所有的栈成员, sharedPtr1 sharedPtr2 执行对应的析构函数-1
独占式智能指针,用得比较少,源码里面找了很多都没看到,主要还是shared_ptr
#include
#pragma once
using namespace std;
template<typename T>
class Ptr{
private:
T * object;// 用于指向管理的对象
int * count;
public:
Ptr(){
count = new int(1);
object = 0;
}
Ptr(T * t): Object(T){
// 只要你传入对象,那么引用计数为1
conut = new int(1);// new 的对象必须是指针接收,new是为了后面操作方便
}
~Ptr(){
// 引用计数减1,为0可以释放对象
if (--(*count) == 0) {
if (object){
delete object;
}
// 归零
delete count;
object = 0;
count = 0;
}
}
Ptr(const Ptr<T> & p){
cout << "拷贝构造函数" << endl;
// ptr2 = ptr1
++(*p.count);
// 当前对象已经被赋值过的情况,再次被赋值,先清空自己。
if (--(*count) == 0) {
if (object){
delete object;
}
// 归零
delete count;
object = 0;
count = 0;
}
object = p.object;
count = p.count;
}
// 自定义 = 号运算符重载
Ptr<T> & operator = (const Ptr<T> & p) {
cout << "= 号运算符重载" << endl;
++(*p.count);
// 当前对象已经被赋值过的情况,再次被赋值,先清空自己。
if (--(*count) == 0) {
if (object){
delete object;
}
// 归零
delete count;
object = 0;
count = 0;
}
object = p.object;
count = p.count;
return *this;
}
int use_count(){
return *this->count;
}
};
class Person{};
int mian(){
return 0;
}
#include
#include // 智能指针的头文件引入
using namespace std;
int mian(){
Person * person1 = new Person();
Person * person2 = new Person();
// 第一种情况
Ptr<Person> ptr; // 给自己引用计数 +1
// 第二种情况
Ptr<Person> ptr1(person1);// 引用计数 +1
/**
按照正常逻辑:ptr1强引用指向person1,ptr2强引用指向ptr1,
ptr2 = ptr1; 执行拷贝构造函数是我们自己定义的
ptr2也持有了person,因为持有ptr1没有意义,我们的目的是管理对象
person1被ptr1和ptr2都持有了,ptr2计数加1变成2,那么弹栈的时候只有ptr1去销毁person
ptr2是不会销毁的,就不会造成二次重复执行销毁代码
*/
// 第三种情况
Ptr<Person> ptr2 = ptr1; // 直接调用拷贝构造函数,不会调用构造函数
//注意调用默认无参数构造
Ptr<Person> ptr3;
// 这种调用的是默认的拷贝函数不是我们自定义的,所以我们要进行=号运算符重载
ptr3 = ptr1;
// 第四种情况
ptr<Person> ptr4(Person);
ptr<Person> ptr5(Person);
// ptr4先清空自己,要不然原来的person会成为野对象
ptr4 = ptr5;
return 0;
}//弹栈会调用析构函数
const修饰的都可以转换
#include
using namespace std;
class Person{
public:
string name = "default";
};
int mian(){
const Person * p1 = new Person();
//p1->name = "aa"; 常量指针 ,不能修改值
Person * p2 = const_cast<Person *>(p1);//将常量指针改成非常量,p2是正常的对象
p2->name = "aaa";//修改成功
//它实际上多了一个对象p2指向的内存地址跟p1是一样的,p1不能修改,但是p2能改啊!
cout << p1->name << endl;//输出aaa
return 0;
}
指针相关的(包括子父类)都可以转换
#include
using namespace std;
class Father{
public:
void show(){}
};
class Son : public Father{
public:
void show(){}
};
int mian(){
int n = 88;
void * pVoid = &n;
int * number = static_cast<int *>(pVoid);
cout << *number << endl;// 88
Father * father = new Father;
father->show();
// static_cast 静态转换看左边(编译器确认)
Son * son = static_cast<Son *>(father);
son->show(); //son的show输出了
delete father;// 回收规则,谁new 就回收 谁
return 0;
}
动态转换:子父类多态 运行期转换
#include
using namespace std;
class Father{
public:
// 动态转换必须让父类成为虚函数
virtual void show(){}
};
class Son : public Father{
public:
void show(){}
};
int mian(){
// 动态转换,在运行期,new Father();已经成定局,所以肯定失败
Father * father = new Father();
//Father * father = new Son;将上面的代码换成这行代码则就可以,因为: new Son
Son * son = dynmic_cast<son *>(father);
// 动态转换是有返回值的, null 转换失败
if (son) { // != null
cout << "成功" << endl;
son->show();
}
return 0;
}
强制转换,比static_cast静态转换强大,静态转换能做的事它都能做。
#include
using namespace std;
class Player{
public:
void show(){}
};
int mian(){
Player * player = new Player;
long player1 = reinterpreet_cast<long>(player); // 把对象变成数值
// 通过数值变成对象
Player * player2 = reinterpreet_cast<Player *>(player1);
return 0;
}