C++ 指针特别篇-指针转换和智能指针

智能指针

智能指针的头文件,#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 shared_ptr1(person1);
内部原理是 :
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); 

你可能感兴趣的:(C++ 指针特别篇-指针转换和智能指针)