智能指针
智能指针的头文件,#include
① shared_ptr
操作引用计数实现共享式拥有的概念。多个智能指针可以指向相同的对象,这个对象和其相关资源会在最后一个被销毁时释放。
#include
#include
using namespace std;
class Person{
public:
virtual ~Person() {
cout << " ~Person 析构" << endl;
}
};
int main(){
Person * person1 = new Person();
// delete person1;
shared_ptr shared_ptr(person1);
return 0;
};
一些有经验的多年C++程序不用,有潜在的bug。特别简单的逻辑可以用。
再看一个例子
#include
#include
using namespace std;
class Person{
public:
virtual ~Person() {
cout << " ~Person 析构" << endl;
}
};
int main(){
Person * person1 = new Person();
Person * person2 = new Person();
//TODO 1------------------
// delete person1;
// shared_ptr shared_ptr(person1);
// ----------------- END
//TODO 1------------------
// person1栈开销,引用计数+1。
shared_ptr shared_ptr1(person1);
shared_ptr shared_ptr2(person2);
// ----------------- END
return 0;
};//函数弹栈 persont1 析构函数 -1 等于0 释放 person1
TODO1 部分的代码,delete person 和 shared_ptr 效果一样,最终都会调用析构函数,这样我们在使用就可以避免忘记写销毁代码delete person
shared_ptr
内部原理是 :
person1栈开销,引用计数+1。
main函数弹栈 persont1 析构函数 -1 等于0 释放 person1
循环依赖问题《错误》演示
// 演示只能指针循环依赖
#include
#include
using namespace std;
class Person2;
class Person1{
public:
shared_ptr person2;
virtual ~Person1() {
cout << " ~Person 析构" << endl;
}
};
class Person2{
public:
virtual ~Person2() {
cout << " ~Person 析构" << endl;
}
shared_ptr person1;
};
int main(){
Person1 * person1 = new Person1();
Person2 * person2 = new Person2();
shared_ptr shared_ptr1(person1);
shared_ptr shared_ptr2(person2);
cout << " shared_ptr1 引用计数" << shared_ptr1.use_count() << endl;
cout << " shared_ptr2 引用计数" << shared_ptr2.use_count() << endl;
// 给person2 赋值
person1->person2 = shared_ptr2;
person2->person1 = shared_ptr1;
cout << " shared_ptr1 引用计数" << shared_ptr1.use_count() << endl;
cout << " shared_ptr2 引用计数" << shared_ptr2.use_count() << endl;
return 0;
}
② weak_ptr 解决循环依赖
weak_ptr是为配合shared_ptr而引入的一种智能指针。主要用于观测资源的引用情况。
它的构造和析构不会引起引用记数的增加或减少。没有重载*和->但可以使用lock获得一个可用的shared_ptr对象。
配合shared_ptr解决循环引用问题
#include
#include
using namespace std;
class Person2;
class Person1{
public:
weak_ptr person2;
virtual ~Person1() {
cout << " ~Person 析构" << endl;
}
};
class Person2{
public:
virtual ~Person2() {
cout << " ~Person 析构" << endl;
}
weak_ptr person1;
};
int main(){
Person1 * person1 = new Person1();
Person2 * person2 = new Person2();
shared_ptr shared_ptr1(person1);
shared_ptr shared_ptr2(person2);
cout << " shared_ptr1 引用计数" << shared_ptr1.use_count() << endl;
cout << " shared_ptr2 引用计数" << shared_ptr2.use_count() << endl;
// 给person2 赋值
person1->person2 = shared_ptr2;
person2->person1 = shared_ptr1;
cout << " shared_ptr1 引用计数" << shared_ptr1.use_count() << endl;
cout << " shared_ptr2 引用计数" << shared_ptr2.use_count() << endl;
return 0;
}
将 声明的shared_ptr 改成weak_ptr
weak_ptr 提供expired 方法等价于 use_count == 0,当expired为true时,lock返回一个存储空指针的shared_ptr
③ unique_ptr
实现独占式引用,保证同一时间只有一个智能指针指向内部对象。
unique_ptr a(new A());
auto_ptr已经不推荐使用
手写智能指针
只能指针可能有三种赋值的方式如下
#include
#include
using namespace std;
class Person {
};
int main() {
Person *person1 = new Person();
Person *person2 = new Person();
// unique_ptr shared_ptr1(person1);
// 情况①
shared_ptr shared_ptr1(person1);
// 情况②
shared_ptr shared_ptr2;
// 情况③
shared_ptr2 = shared_ptr1;
return 0;
}
根据这个分析,我们需要实现,构造函数,拷贝构造函数,= 运算符重载。默认创建对象引用数+1
-> 具体实现
#ifndef TEMPC_CUSTOMPTR_H
#define TEMPC_CUSTOMPTR_H
#pragma once
#include
using namespace std;
template
class Ptr{
private:
T * object;
int * count;
public:
Ptr() {
count = new int(1);
object = 0;
}
Ptr(T *t) : object(t) {
count = new int(1);
}
virtual ~Ptr() {
if(--(*count) == 0){
if(object){
delete object;
}
delete count;
count = 0;
object = 0;
}
}
// 操作符号重载
Ptr &operator = (const Ptr & p){
cout << "操作符重载" << endl;
++(*p.count);
if(--(*count) == 0) {
if(object){
delete object;
}
delete count;
}
object = p.object;
count = p.count;
return *this;
}
// 拷贝构造函数
Ptr(const Ptr &p){
++(*p.count);
object = p.object;
count = p.count;
}
};
#endif //TEMPC_CUSTOMPTR_H
指针的转换
const_cast
常量指针转换非常量
const Person *p1 = new Person();
这么做是错误的,p1->name = "David"
但是转换后是可以赋值,并且再次获取name值发生了更改
#include
using namespace std;
class Person {
public :
string name = "default";
};
int main() {
const Person *p1 = new Person();
// p1->name = "David";// 报错:常量指针,不修改值
// 常量指针转换非常量
Person *p2 = const_cast(p1);
p2->name = "David";
cout << p1->name << endl;
return 0;
}
static_cast
static_cast 指针相关的操作 可以用 static_cast
静态转换看左边(编译期)
#include
using namespace std;
class PClass {
public :
void show() {
cout << "p show" << endl;
}
};
class CClass :public PClass{
public :
void show() {
cout << "c show" << endl;
}
};
int main() {
int n = 88;
void *pVoid = &n;
int *number = static_cast(pVoid);
cout << *number << endl;
PClass * pClass = new PClass;
pClass->show();
// 静态转换看左边(编译期)
CClass * cclass = static_cast(pClass);
cclass->show();
delete pClass;
return 0;
}
dynamic_cast
dynamic 字符类多态 运行期 转换
#include
using namespace std;
class PClass {
public :
virtual void show() {
cout << "p show" << endl;
}
};
class CClass :public PClass{
public :
void show() {
cout << "c show" << endl;
}
};
int main() {
PClass * pClass = new CClass();
// PClass * pClass = new PClass();
// 动态转换(运行期)
CClass * cClass = dynamic_cast(pClass);
if(cClass){
cout << "success cast";
cClass->show();
} else {
cout << "fail cast" << endl;
}
CClass * t = new CClass();
PClass * p = dynamic_cast(t);
if(p){
cout << "p success cast";
p->show();
} else {
cout << "p fail cast" << endl;
}
return 0;
}
reinterpret_cast
reinterpret_cast 强制转换 比 static_cast要强大, static_cast能够做的事情,
reinterpret_cast强制转换都可以,同时并且附加 新功能
常见的long 和对象的转换
#include
using namespace std;
class Player {
public :
virtual void show() {
cout << "Player" << endl;
}
};
int main() {
Player * player = new Player();
long playerValue = reinterpret_cast(player);
cout << playerValue << endl;
Player *p = reinterpret_cast(playerValue);
p->show();
cout << player << endl;
cout << p << endl;
return 0;
}
nullptr
nullptr 出现的目的是为了替代 NULL。 同时拥有更多的特性 例如:可以调用到指针参数的函数。
前面多线程补充点,详细说过,nullptr就是解决 NULL 宏定义在C++的二义性
void test(int* i){
}
void test(int i){
}
//现在调用哪一个test? test(int)
test(9);
//调用test(int* i)
test(nullptr);