智能指针
参考:https://blog.csdn.net/flowing_wind/article/details/81301001
我们知道除了静态内存和栈内存外,每个程序还有一个内存池,这部分内存被称为自由空间或者堆。程序用堆来存储动态分配的对象即那些在程序运行时分配的对象,当动态对象不再使用时,我们的代码必须显式的销毁它们。
在C++中,动态内存的管理是用一对运算符完成的:new和delete,new:在动态内存中为对象分配一块空间并返回一个指向该对象的指针,delete:指向一个动态独享的指针,销毁对象,并释放与之关联的内存。
动态内存管理经常会出现两种问题:一种是忘记释放内存,会造成内存泄漏;一种是尚有指针引用内存的情况下就释放了它,就会产生引用非法内存的指针。
为了更加容易(更加安全)的使用动态内存,引入了智能指针的概念。智能指针的行为类似常规指针,重要的区别是它负责自动释放所指向的对象。标准库提供的两种智能指针的区别在于管理底层指针的方法不同,
shared_ptr允许多个指针指向同一个对象,unique_ptr则“独占”所指向的对象。标准库还定义了一种名为weak_ptr的伴随类,它是一种弱引用,指向shared_ptr所管理的对象,这三种智能指针都定义在memory头文件中。
常用智能指针:shared_ptr,unique_ptr和weak_ptr
shared_ptr允许多个指针指向同一个对象,unique_ptr则“独占”所指向的对象。标准库还定义了一种名为weak_ptr的伴随类,它是一种弱引用,指向shared_ptr所管理的对象,这三种智能指针都定义在memory头文件中。
shared_ptr<int> p3 = make_shared<int>(42);
shared_ptr<string> p4 = make_shared<string>(10,'9');
shared_ptr<int> p5 = make_shared<int>();
//可以通过调用release或reset将指针所有权从一个(非const)unique_ptr转移给另一个unique
//将所有权从p1(指向string Stegosaurus)转移给p2
unique_ptr<string> p2(p1.release());//release将p1置为空
unique_ptr<string> p3(new string("Trex"));
//将所有权从p3转移到p2
p2.reset(p3.release());//reset释放了p2原来指向的内存
shared_ptr和unique_ptr用法:
shared_ptr<T> sp; //空指针,可以执行类型为T 的对象
unique_ptr<T> up;
p //p看做一个条件判断,若p指向一个对象,则为true
*p //获取它指向的对象
p->mem //等价于(*p).mem
p.get() //返回P中保存的指针。
swap(p,q) //交换p和q中的指针
p.swap(q)
share_ptr:
make_share<T> (args) //返回一个shared_ptr,指向一个动态分配的类型为T的对象,使用args初始化。
share_ptr<T> p(q) //p是shared_ptr q的拷贝,此时会增加q中计数器,q中的指针必须转换为T*;
p = q //p和q都是shared_ptr,所保存的指针必须能相互转换。此操作会递减p的引用计数,
//递增q的引用计数。若p的引用计数为0,则将其管理的内存释放。
p.unique() //若p.use_count()为1,则返回 true;否则返回 false
p.use_count() //返回与p共享对象的智能指针数量;可能很慢,主要用于调试。
unique_ptr:
//由于一个unique_ptr拥有它指向的对象,因此unique_ptr不支持普通的拷贝或赋值操作。
unique_ptr<T> u1 // 空unique_ptr,可以指向类型为T的对象。u1会使用delete来释放它的指针;
unique_ptr<T,D> u2 // u2会使用一个类型为D的可调用对象来释放它的指针。
unique_ptr<T,D> u(d) // 空unique_ptr,指向类型为T的对象,用类型为D的对象d代替delete
u=nullptr // 释放u指向的对象,将u置为空
u.release() // u放弃对指针的控制,将u置为空
u.reset() //释放u指向的对象
u.reset(q) //如果提供了指针q,将u指向这个对象,否则将u置为空。
u.reset(nullptr)
weak_ptr:
weak_ptr是一种不控制所指向对象生存期的智能指针,它指向一个由shared_ptr管理的对象,将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。一旦最后一个指向对象的shared_ptr被销毁,对象就会被释放,即使有weak_ptr指向对象,对象还是会被释放。
weak_ptr<T> W // 空weak_ptr 可以指向为T的对象
weak_ptr<T> W(sp) //与shared_ptr sp 指向相同对象 weak_ptr
w = p // P可以是share_ptr 或weak_ptr
w.reset() //w 为空
w.use_count //与w共享对象的shared_ptr竖向
w.expired() //w.use_count() 为0 ,返回true,否则返回为false
w.lock() //如果expired 为true,则返回一个空shared_ptr,否则返回一个指向w对象的shared_ptr
weak_ptr 举例
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
class Test{
public:
Test(int d = 0) : data(d){cout << "new" << data << endl;}
~Test(){cout << "del" << data << endl;}
void func(){cout << "func" << endl;}
private:
int data;
};
class teacher{
public:
teacher(){cout << "teacher()" << endl;}
~teacher(){cout << "del teacher" << endl;}
shared_ptr<student> stu;
};
class student{
public:
student(){cout << "student()" << endl;}
~student(){cout << "del student" << endl;}
//如果换成shared_ptr<teacher> tea;就会形成循环引用,导致内存泄漏
weak_ptr<teacher> tea;
};
int main(){
//用weak_ptr解决了share_ptr循环引用,导致的内存不能释放的问题
shared_ptr<teacher> tptr(new teacher);//计数器1
shared_ptr<student> sptr(new student);//计数器1
tptr->stu = sptr;//sptr的计数器2
sptr->tea = tptr;//不增加tptr的引用计数,因为tea是weak指针,如果tea是shared_ptr容易导致循环引用
cout << tptr.use_count() << endl;//1
cout << sptr.use_count() << endl;//2
return 0;
}
std::move
类型转换static_cast
std::move语句可以将左值变为右值而避免拷贝构造。将对象的状态或者所有权从一个对象转移到另一个对象。
左值:放在等号左边的值,可以被赋值: a; ++a; a;*a;a.m;a->m;a[m]
右值:放在等号右边的值,不能被赋值;a+b; a++; a&&b; a<b; &a
深拷贝:A先申请出一片新的空间,完全复制B的内容到新空间中;
浅拷贝:A复制B指针,将自己的指针指向B的内容地址,A、B公用一块内存地址;
A = std::move(B); A 对 B 实现浅层拷贝,为了防止B的改变影响到A ,对B清除。
参考:https://www.lanindex.com/stdmove%E5%AE%9E%E9%99%85%E5%BA%94%E7%94%A8%E5%88%86%E6%9E%90/
举例:
#include <iostream>
#include <utility>
#include <vector>
#include <string>
int main()
{
std::string str = "Hello";
std::vector<std::string> v;
//调用常规的拷贝构造函数,新建字符数组,拷贝数据
v.push_back(str);
std::cout << "After copy, str is \"" << str << "\"\n";//str is "hello"
//调用移动构造函数,掏空str,掏空后,最好不要使用str
v.push_back(std::move(str));
std::cout << "After move, str is \"" << str << "\"\n";//str is ""
std::cout << "The contents of the vector are \"" << v[0]
<< "\", \"" << v[1] << "\"\n";
}
原文链接: https://www.cnblogs.com/heimazaifei/p/12133715.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/191300
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!