unique_ptr
同一时刻只能有一个unique_ptr指向这个对象(这块内存),当unique_ptr被销毁时,它所指向的对象也会被销毁
1.形式:
unique_ptr<指向的对象类型> 智能指针变量名
1.常规初始化 和new配合
unique_ptr<int> p2(new int(500)); //直接把它绑定到new返回的指针上
2.make_unique函数,C++11里面没有这个函数,但C++14中有
unique_ptr<int> p1 = std::make_unique<int>(100);
auto p2 = std::make_unique<int>(200);
//如果不用make_unique函数,那就只能这样写
shared_ptr<int> p3(new int(100)); //int重复两次,而且不能用auto简写,要不然p3就成裸指针了
2.常用操作
—不支持的操作
unique_ptr<string> ps1(new string("I love China!"));
unique_ptr<string> ps2(ps1); //错误,它不支持复制
unique_ptr<string> ps3 = ps1 //错误,它不支持复制
unique_ptr<string> ps4;
ps4 = ps1;//错误,不支持赋值
—移动语义
虽然它不支持复制,但是它支持移动,通过std::move来把一个unique_ptr转移到其他的unique_ptr
unique_ptr<string> ps1(new string("I love China!"));
unique_ptr<string> ps3 = std::move(ps1); //转移后ps1为空,ps3指向原来ps1所指
—release成员函数
让指针为空,但是内存还在
放弃对指针的控制权啊(切断智能指针和其所指向的对象之间的联系),返回指针(裸指针),将智能指针置空,返回的这个裸指针可以手动delete释放,也可以用来初始化另外一个智能指针,或者给另外一个智能指针赋值
unique_ptr<string> ps1(new string("I love China!"));
unique_ptr<string> ps2(ps1.release());
if(ps1 == nullptr) //条件成立
{
cout << "ps1被置空" << endl;
}
ps2.relase(); //错误,因为这会导致内存泄露,返回了一个裸指针,但是没有释放
//正确
string * temp = ps2.release(); // 或者auto temp = ps.release();
delete temp;
—reset成员函数
都会释放原来的内存,指针释放不释放不一定
若reset不带参数时,则释放pi指向的对象,把pi置空
若带参数,则释放pi原来指向的内存,让pi指向新内存
//不带参数
unique_ptr<string> prs(new string("I love China!"));
prs.reset(); //不带参数,prs指向的对象释放,prs置空
if(prs == nullptr) //成立
{
cout << "prs被置空" << endl;
}
//带参数
unique_ptr<string> ps1(new string("I love China1!"));
unique_ptr<string> ps2(new string("I love China2!"));
ps2.reset(ps1.release()); //reset释放ps2原来指向的内存,让ps2指向ps1所指向的内存,同时ps1置空
ps2.reset(new string("I love China1")) //reset参数可以时一个裸指针,reset释放原来ps2指向的内存,让ps2指向新new出来的string
— = nullptr
释放内存,释放指针
— 指向数组
std::unique_ptr<int[]> ptrarray(new int[10]); //前面带上空括号[]表示是数组,下面行才可以用[下标]来引用数组元素
ptrarray[0] = 12; //数组提供索引运算符[]
ptrarray[1] = 22;
ptrarray[2] = 32; //能访问的下标是0~9,不要超过这个范围
—get成员函数
返回智能指针中保存的对象(裸指针),小心使用,若智能指针释放了所指的对象,则返回的对象也就变得无效了
unique_ptr<string> ps1(new string("I Love China!"));
string * ps = ps1.get();
const char * p1 = ps->c_str();
*ps = "aaa";
const char * p2 = ps->c_str();
//发现p1和p2是不同的内存地址,这是string内部工作机制决定的
``c_str是 C++ 中
string类的一个成员函数,它的作用是返回一个指向
string对象内部存储的字符串的指针。这个指针指向的是一个以空字符(
’\0’)结尾的字符数组,因此我们可以将它传递给一些需要以空字符结尾的字符串作为参数的函数,例如
printf` 函数。
#include <iostream>
#include <string>
int main() {
std::string str = "Hello, world!";
const char* cstr = str.c_str();
std::cout << cstr << std::endl;
return 0;
}
在这个例子中,我们定义了一个 string
类型的变量 str
,并将其初始化为 "Hello, world!"
。然后,我们调用 str
的 c_str
函数来获取一个指向它内部存储的字符串的指针,并将这个指针赋值给了 cstr
。最后,我们使用 cout
来输出这个指针所指向的字符串
std::cout << cstr << std::endl;
这行代码输出的结果是 cstr
所指向的内容,即字符串 "Hello, world!"
。在 C++ 中,当我们使用 cout
来输出一个 char
类型的指针时,它会自动输出这个指针所指向的以空字符('\0'
)结尾的字符串。因此,在上面的例子中,cstr
指向的是一个以空字符结尾的字符串,所以当我们使用 cout
来输出 cstr
时,它会自动输出这个字符串。
上面的p1
和 p2
的内存地址不同是因为 string
类型的对象在修改其内容时,可能会重新分配内存来存储新的字符串。当我们修改 string
对象的内容时,它所管理的内存可能会发生变化,因此我们不能保证在修改前后通过调用 c_str
函数获取的指针指向相同的内存地址
为什么有get这个函数呢,因为考虑到有些函数的参数需要的是一个内置指针(裸指针),所以选择 通过get取得这个内置指针并传递给这样的函数,但是注意不要delete这个get到的指针,否则后果很严重
举个例子
#include <iostream>
#include <memory>
void print(int* ptr) {
std::cout << *ptr << std::endl;
}
int main() {
std::unique_ptr<int> p(new int(42));
print(p.get());
return 0;
}
—*解引用
std::unique_ptr<int[]> ptr(new int[10]);//对于定义的内容是数组,是没有*解引用运算符的
*ptr;//错误
—swap成员函数
交换两个智能指针指向的对象
std::swap(p1, p2);
//或者
p1.swap(p2);
—智能指针名字作为判断条件
unique_ptr<string> ps1(new string("I Love China!"));
//若ps1指向了一个对象,则为true
if(ps1) //成立
{
cout << "ps1指向了一个对象" << endl;
}
3.尺寸问题
一般情况下,unique_ptr大小和裸指针一样,足够小,足够快,但是如果增加了删除器,则大小可能变,可能不变
string * p;
int i = sizeof(p); //4字节
unique_ptr<string> ps1(new string("I Love China!"));
int j = sizeof(ps1); //4字节
—如果删除器是lambda表达式这种匿名对象,则大小不变
–如果删除器是一个函数,则大小会变
unique_ptr变大肯定对效率有影响,所以把一个函数当作删除器,还是要慎用,这一点和shared_ptr不同,它是不管指定什么删除器,大小都是裸指针的2倍
- 点赞
- 收藏
- 关注作者
评论(0)