目 录CONTENT

文章目录

智能指针和函数参数与返回值

WenzhouXv
2023-08-14 / 0 评论 / 0 点赞 / 102 阅读 / 0 字

C++智能指针和函数参数与返回值

unique_ptr

  • 管理单个对象(例如以 new 分配)
  • 管理动态分配的对象数组(例如以 new[] 分配)
  • 类满足可移动构造 (MoveConstructible) 和可移动赋值 (MoveAssignable) 的要求,但不满足可复 制构造 (CopyConstructible) 或可复制赋值 (CopyAssignable)

智能指针和数组初始化方式分析

#include <iostream>
using namespace std;
class Data
{
public:
    static int count;
    int index = 0;
    Data() 
    { 
        count++; 
        index = count; 
        cout << index << ":Create Data" << endl; 
    }
    ~Data() 
    { 
        cout << index << ":Drop Data" << endl; 
    }
};
int Data::count = 0;
int main(int argc,char *argv[])
{
    std::cout << "cppds.com"<<endl;
    //1 unique_ptr 初始化
    // RAII资源获取即初始化(Resource Acquisition Is Initialization)
    {
        unique_ptr<int> p1(new int);
        unique_ptr<Data> p2(new Data);
        cout << "======1======" << endl;
        auto p3 = make_unique<Data>();

        //空智能指针
        unique_ptr<Data> p4;
        unique_ptr<int[]> pa1 = make_unique<int[]>(1024);
        unique_ptr<int[]> pa2(new int[1024]);
        unique_ptr<Data[]> pa3(new Data[3]);


    }
    cout << "======2======" << endl;
    getchar();
    return 0;
}

智能指针和数组的访问

int main(int argc,char *argv[])
{
    std::cout << "cppds.com"<<endl;
    {
        // unique_ptr智能指针访问和移动构造赋值
        *p1 = 10;
        cout << "p1 value=" << *p1 << endl;
        cout << "(*p2).index ="<<(*p2).index << endl;
        cout << "p2->index = "<<p2->index << endl;
        auto d1 = new Data();
        unique_ptr<Data> p5(d1);
        cout << "p5 address:" << p5<<endl;
        cout << "d1 address:" << d1 << endl;
        cout << "p5.get():" << p5.get() << endl;
        //unique_ptr智能指针数组访问
        pa2[1] = 100;
        pa2[0] = 1;
        cout << " pa3[1].index = " << pa3[1].index << endl;
        cout << "pa3.get()[2].index = " << pa3.get()[2].index << endl;
    }
}

重置和移动内存资源

int main(int argc,char *argv[])
{
    std::cout << "cppds.com"<<endl;
    //1 unique_ptr 初始化
    // RAII资源获取即初始化(Resource Acquisition Is Initialization)
    {
        //重置和移动内存资源
        // unique_ptr
        unique_ptr<Data> p6(new Data());
        // 不可复制构造
        //unique_ptr<Data> p7 = p6;
        //不可以赋值
        //p7 = p6;
        //支持移动构造 p6释放所有权 转移到p7
        unique_ptr<Data> p7 = move(p6);
        unique_ptr<Data> p8(new Data());
        
        //支持移动赋值
        p7 = move(p8);

        //重置空间,原空间清理
        p7.reset(new Data());
    }
}

释放所有权和自定义空间删除方法

struct XPacket
{
    unsigned char* data = nullptr;
    int size = 0;
};
class PacketDelete
{
public:
    void Close() 
    { 
        cout << "Call PakcetDelete Close!" << endl; 
    }
    void operator()(XPacket* p) const
    {
        cout << "call PacketDelete()" << endl;
        delete p->data;
        delete p;
    }


};
int main(int argc,char *argv[])
{
    {
        cout << "begin p7 = nullptr" << endl;
        //释放所有权和自定义空间删除方法
        //主动释放空间
        p7 = nullptr;
        unique_ptr<Data> p9(new Data);
        //释放所有权
        auto ptr9 = p9.release();
        delete ptr9;
        cout << "end p7 = nullptr" << endl;
        
        //自定义空间删除方法
        unique_ptr<XPacket,PacketDelete> pd1(new XPacket);
        unique_ptr<XPacket, PacketDelete> pd2(new XPacket);
        pd2.get_deleter().Close();
        pd2.get_deleter()(pd2.get());
        pd2.release();
    }
}

shared_ptr

  • 共享所有权的智能指针.多个shared_ptr指向同一对象
  • 可复制构造(CopyConstructible)
  • 可复制赋值(CopyAssignable)
  • 数据访问非线程安全
  • shared_ptr 的控制块是线程安全

图解shared_ptr共享智能指针原理分析

image-20230814064750587

共享指针初始化和清理

#include <iostream>
using namespace std;
class XData
{
public:
    XData()
    {
        cout << "Create XData" << endl;
    }
    ~XData()
    {
        cout << "Drop XData" << endl;
    }
};
int main(int argc,char *argv[])
{
    std::cout << "cppds.com" << endl;
    {
    //1 初步使用
    shared_ptr<int> sp1(new int);
    shared_ptr<int[]> sp2(new int[1024]);
    *sp1 = 10;
    sp2[0] = 100;
    auto d1 = sp1.get();
    auto sp3 = make_shared<XData>();
    cout << "sp3.use_count() = " << sp3.use_count() << endl;

    //2 可复制构造 和赋值
    auto sp4 = sp3;
    cout << "sp4 = sp3 ; sp3.use_count() = " << sp3.use_count() << endl;
    cout << "sp4.use_count() = " << sp4.use_count() << endl;
    auto sp5 = make_shared<XData>();
    sp4 = sp5;
    cout << "sp4 = sp5 ; sp3.use_count() = " << sp3.use_count() << endl;
    {
        auto sp6 = sp3;
        cout << "sp6 = sp3 ; sp3.use_count() = " << sp3.use_count() << endl;
    }
    cout << "} sp3.use_count() = " << sp3.use_count() << endl;
    sp3.reset(); //-1 如果引用计数为0 则清理空间
    cout << "sp3.reset() sp3.use_count() = " << sp3.use_count() << endl;
    }
    cout << "after }" << endl;
    return 0;
}

定制删除函数

定义删除函数

void DelData(XData* p)
{
    cout << "call DelData" << endl;
    delete p;
}

实现

int main(int argc,char *argv[])
{
    //3 shared_ptr定制删除函数
    {
        shared_ptr<XData> sp7(new XData, DelData);
    }
    return 0;
}

lambda表达式

int main(int argc,char *argv[])
{
    //3 shared_ptr定制删除函数
    {
        shared_ptr<XData> sp8(new XData, [](auto p) {//
            cout << "Call delete lambda" << endl;
            delete p;
            });
    }
    return 0;
}

指向对象的不同成员

不太明白这种用法

修改类

class XData
{
public:
    XData()
    {
        cout << "Create XData" << endl;
    }
    ~XData()
    {
        cout << "Drop XData" << endl;
    }
    int index1 = 0;
    int idnex2 = 0;
};

实现

 int main(int argc,char *argv[])
{
    {
        shared_ptr<XData> sc1(new XData);
        cout << "sc1 use_count=" << sc1.use_count() << endl;
        shared_ptr<int> sc2(sc1, &sc1->idnex2);
        shared_ptr<int> sc3(sc1, &sc1->index1);
        cout << "sc1 use_count=" << sc1.use_count() << endl;
    }
}

weak_ptr

  • use_count: 返回管理该对象的 shared_ptr 对象数量
  • lock:创建管理被引用的对象的shared_ptr

循环引用问题

class B;
class A
{
public:
	A()
	{
		cout << "Create A" << endl;
		cout << "b1.use_count()" << b1.use_count() << endl;
	}
	~A()
	{
		cout << "Drop A" << endl;
		cout << "b1.use_count()" << b1.use_count() << endl;
	}
	std::shared_ptr<B> b1;
};
class B
{
public:
	B()
	{
		cout << "Create B" << endl;
		//cout << "a1.use_count()" << a1.use_count() << endl;
	}
	~B()
	{
		cout << "Drop B" << endl;
		cout << "a1.use_count()" << a1.use_count() << endl;
	}
	std::shared_ptr<A> a1;
};

int main(int argc, char* argv[])
{
    auto a = make_shared<A>(); //=1
    auto b = make_shared<B>(); //=1
    a->b1 = b; //+1 =2
    cout << "a->b1 = b b.use_count()=" << b.use_count() << endl;
    b->a1 = a; //+1 =2
    cout << "b->a1 = a a.use_count()=" << a.use_count() << endl;
}

解决循环引用

use_count 返回管理该对象的 shared_ptr 对象数量 expired 检查被引用的对象是否已删除 lock 创建管理被 引用的对象的 shared_pt

修改A类

class A
{
public:
    A() { cout << "Create A" << endl; }
    ~A() { cout << "Drop A" << endl; }
    void Do()
    {
        cout <<"Do b2.use_count() = "<< b2.use_count() << endl;
        auto b = b2.lock(); //复制一个共享智能指针 引用计数+1
        cout << "Do b2.use_count() = " << b2.use_count() << endl;
    }
    shared_ptr<B> b1;
    weak_ptr<B> b2;
};

实现

class B
{
public:
    B() { cout << "Create B" << endl; }
    ~B() { cout << "Drop B" << endl; }
    shared_ptr<A> a1;
};
int main(int argc, char* argv[])
{
    //a 出作用域 a.use_count - 1 = 1 a资源不释放 a.b1不释放 
    // ?  b.use_count = 2
    // b 出作用域 b.use_count - 1 = 1 b资源不释放 b.a1 不释放
    // ? b.use_count = 1 a.use_count = 1
    {
        auto a = make_shared<A>(); //=1
        auto b = make_shared<B>(); //=1
        a->b2 = b; //=1
        a->Do();
        cout << "a->b1 = b b.use_count()=" << b.use_count() << endl;
        b->a1 = a; //+1 =2
        cout << "b->a1 = a a.use_count()=" << a.use_count() << endl;
    }
    return 0;
}

指针和函数参数返回值

指针作为参数设计说明

  • 传递输入内存,需要提供内存大小(数组到指针无法知道大小),并设置为const
  • 传递输出内存,同样需要提供内存大小,防止溢出
  • 如果指向函数中创建堆内存,需要传递指针引用或者指向指针的指针
  • 通过返回值只能返回堆中空间,比较危险,需要函数中注释说明,防止内存泄漏

指针作为函数参数传递-使用模板传递数组

void PtrFunction(const char* data, int size)
{
    cout <<"sizeof(data) = "<< sizeof(data) << endl;
}

//经过参数传递 数组转成指针
void PtrFunction(const char data[])
{
    cout << "sizeof(data) = " << sizeof(data) << endl;
}

//传递参数 获取数组大小
template <class Ty ,size_t Size>
void TestMemArr(Ty(&data)[Size])
{
    cout << "sizeof(data)=" << sizeof(data) << endl;
}

//指针输出
//1 修改原内存
//2 使用函数内创建的内存
char* TestMem()
{
    //error 不能返回栈中空间
    char buf[1024] = "test";
    return buf;
}

void TestMem(char* out)
{
    //修改的局部变量 内存泄漏
    out = new char[1024];
}

//返回的空间需要注释,由用户释放
int TestMem(char** out)
{
    int size = 1024;
    //修改的局部变量
    *out = new char[size];
    return size;
}

实现

int main()
{
    std::cout << "cppds.com" << endl;
    char data[] = "test mem ptr";
    PtrFunction(data, sizeof(data));
    PtrFunction(data);
    TestMemArr(data);
    cout << data << endl;

    //异常空间已经释放,结果不确定
    cout << TestMem() << endl;

    char* out = nullptr;
    TestMem(out);
    cout << "out  " << (int)out << endl;
    TestMem(&out);
    cout << "out  " << (int)out << endl;
    delete out;
}

智能指针作为函数的参数和返回值unique_ptr

//智能指针作为函数参数和返回值
class XData
{
public:
    XData() 
    { 
        cout << "Create XData" << endl; 
    }
    ~XData() 
    { 
        cout << "Drop XData" << endl; 
    }
    int index = 0;
};
unique_ptr<XData> TestUnique(unique_ptr<XData> ptr)
{
    cout << "ptr->index=" << ptr->index << endl;
    unique_ptr<XData> re(new XData);
    re->index = 222;
    // 编译器优化 1 如果返回值支持move 编译器自动调用move,不支持调用拷贝构造
    return re;
}

int main()
{
    {
     	unique_ptr<XData> ptr1(new XData);
        ptr1->index = 111;
        cout << "ptr1->index=" << ptr1->index << endl;
        auto re = TestUnique(move(ptr1));
        cout << "re->index=" << re->index << endl;
        if (!ptr1)
        {
            cout << "ptr1 empty" << endl;
        }
        else
        {
            cout << "ptr1->index=" << ptr1->index << endl;
        }
    }
}


案例

使用string作为函数参数内存的输入和输出

#include <iostream>
#include <string>

using namespace std;

void TestString(string &in_data,string &out_data)
{
    cout << "in_data=" << in_data << endl;
    cout << in_data.size() << endl;
    cout << "in_data addr:" << (long long)in_data.data() << endl;
    out_data.resize(1024);
    cout << "out_data addr:" << (long long)out_data.data() << endl;
}

int main(int argc,char *argv[])
{

    // 使用string 传递和获取内存
    // 不需要考虑内存释放
    // 可以获取已申请内存大小

    std::cout << "cppds.com" << endl;

    string str1;
    str1.resize(1024);
    auto data = const_cast<char*>(str1.data());
    cout << "addr:" << (long long)data << endl;
    memset(data, 'A', 5);
    cout << str1 << endl;
    string out_str;
    TestString(str1, out_str);
    cout << "out_str size = " << out_str.size() << endl;
    cout << "out_str addr:" << (long long) out_str.data() << endl;



    
    return 0;
}

使用vector传递内存并接受函数返回的内存空间

#include <iostream>
#include <string>
#include <vector>
using namespace std;
class XData
{
public:
    XData()
    {
        cout << "Create XData" << endl;
    }
    XData(const XData& d)
    {
        this->index = d.index;
        cout << "Copy XData " << index << endl;
    }
    XData& operator=(const XData& d)
    {
        this->index = d.index;
        cout << "=XData" << index << endl;
        return *this;
    }
    ~XData()
    {
        cout << "Drop XData " << index << endl;
    }

    int index = 0;
};

vector<XData> TestVec(vector<XData>& data)
{
    cout << "TestVec data:" << data.data() << endl;
    vector<XData> re;
    re.resize(3);
    cout << "re.data()" << re.data() << endl;
    cout << "re Byte=" << re.size() * sizeof(XData) << endl;

    return re;
}

int main(int argc,char *argv[])
{
    // 使用vector 传递和获取内存
    // 功能等同于string
    // 可用传递不同的类型
    // 可以用作返回值支持move
    {
    vector<XData> vd;
    XData d;
    d.index = 1;
    vd.push_back(d);
    d.index = 2;
    vd.push_back(d);
    d.index = 3;
    vd.push_back(d);
    cout << "vd.data() = "<<vd.data() << endl;
    auto rd = TestVec(vd);
    cout << "rd.data()" << rd.data() << endl;
    }
    getchar();
    return 0;
}


其他

unique 尤里克

shared 喜爱的

weak 维克

0
c++
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区