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共享智能指针原理分析
共享指针初始化和清理
#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 维克
评论区