文章目录
- RAII机制
- unique_ptr
-
- shared_ptr
-
- weak_ptr
-
RAII机制
RAII即Resource Acquisition Is Initialization(资源获取即初始化),RAII是C++语法体系中的一种常用的合理管理资源避免出现内存泄漏的常用方法。用对象管理资源,利用C++构造的对象最终会被对象的析构函数销毁的原则。RAII的做法是使用一个对象,在其构造时获取对应的资源,在对象生命期内控制对资源的访问,使之始终保持有效,最后在对象析构的时候,释放构造时获取的资源。
unique_ptr
注意事项
- 使用智能指针时避免手动释放资源,否则自动释放资源时候会出现重复释放问题
- 如果使用了release()接口获取原始指针,注意需要自己手动释放资源
- 作为函数参数按值传递时,注意所有权的转移
- 不支持拷贝构造和拷贝赋值,可以使用移动构造和移动赋值
- 当使用const修饰时,独占的资源不可以修改
基本用法
接口 |
返回值 |
说明 |
get() |
原始指针类型 |
获取智能指针管理的原始指针类型 |
reset() |
无 |
释放资源并将指针置空,或释放原始资源然后接管新资源 |
release() |
原始指针类型 |
返回原始指针类型,然后释放对原始指针的所有权 |
swap() |
无 |
交换两个指针的所有权 |
class MyClass
{
public:
MyClass()
{
std::cout<<"structure pointer." << std::endl;
};
MyClass(const std::string &str)
: m_strName(str)
{
std::cout<<"structure " << m_strName << " pointer." << std::endl;
};
~MyClass()
{
std::cout<<"destructed " << m_strName << " pointer." << std::endl;
};
void doSomething()
{
std::cout << m_strName << " doSomething"<<std::endl;
}
void setName(const std::string& strName)
{
m_strName = strName;
}
void setFriend(std::shared_ptr<MyClass> pFriend)
{
m_friend = pFriend;
}
private:
std::string m_strName;
std::weak_ptr<MyClass> m_friend;
};
std::unique_ptr<MyClass> pUniquePtr1 = std::make_unique<MyClass>("class01");
std::unique_ptr<MyClass> pUniquePtr2(new MyClass("class02"));
MyClass *pTr = new MyClass("class03");
std::unique_ptr<MyClass> pUniquePtr3(pTr);
std::unique_ptr<MyClass> pUniquePtr4(std::move(pUniquePtr2));
pUniquePtr4->setName("class04");
std::cout << "pUniquePtr2=" << std::hex << pUniquePtr2.get() << std::endl;
std::unique_ptr<MyClass> pUniquePtr5;
std::cout << "pUniquePtr1=" << std::hex << pUniquePtr1.get() << std::endl;
std::cout << "pUniquePtr5=" << std::hex << pUniquePtr5.get() << std::endl;
pUniquePtr5 = std::move(pUniquePtr1);
std::cout << "pUniquePtr1=" << std::hex << pUniquePtr1.get() << std::endl;
std::cout << "pUniquePtr5=" << std::hex << pUniquePtr5.get() << std::endl;
std::cout << typeid((pUniquePtr3.get())).name() << std::endl;
std::cout << "pUniquePtr3 = " << std::hex << pUniquePtr3.release() << std::endl;
std::cout << "after call release:" << std::hex << pUniquePtr3.get() << std::endl;
(*pUniquePtr5).doSomething();
pUniquePtr5->doSomething();
pUniquePtr5.reset(new MyClass("class06"));
std::unique_ptr<MyClass[]> pUniquePtr6(new MyClass[3]{{"class07"}, {"class08"}, {"class09"}});
pUniquePtr6[0].doSomething();
auto funcDel = [](MyClass *ptr){
std::cout << "customer delete." << std::endl;
delete []ptr;
};
std::unique_ptr<MyClass, void(*)(MyClass *ptr)> pUniquePtr7(new MyClass[2]{{"class10"}, {"class11"}}, funcDel);
std::unique_ptr<MyClass> pUniquePtr8(new MyClass("class swap"));
pUniquePtr8.swap(pUniquePtr5);
pUniquePtr8->doSomething();
pUniquePtr5->doSomething();
使用场景
- 作为函数局部变量(最常用)
函数内或局部作用域中使用,在离开作用域后会自动释放资源,有效避免资源泄露
int main()
{
{
std::unique_ptr<MyClass> pTemp = std::make_unique<MyClass>("temp pointer");
pTemp->doSomething();
}
std::cout<< "pTemp have been released" << std::endl;
return 0;
}
- 作为函数参数按值传递
void passByValue(std::unique_ptr<MyClass> ptr)
{
ptr->doSomething();
ptr->setName("pass by value");
}
int main()
{
std::unique_ptr<MyClass> pUniquePtr9 = std::make_unique<MyClass>("create pass by value pointer");
passByValue(std::move(pUniquePtr9));
return 0;
}
- 作为函数参数按引用传递
void passByReference(std::unique_ptr<MyClass> &ptr)
{
ptr->doSomething();
ptr->setName("pass by reference");
}
int main()
{
std::unique_ptr<MyClass> pUniquePtr10 = std::make_unique<MyClass>("create pass by reference pointer");
passByReference(pUniquePtr10);
pUniquePtr10->doSomething();
return 0;
}
- 函数返回智能指针对象(不常用)
std::unique_ptr<MyClass> getUniquePtr()
{
std::unique_ptr<MyClass> tmpPtr = std::make_unique<MyClass>("local unique pointer");
return tmpPtr;
}
int main()
{
getUniquePtr()->doSomething();
return 0;
}
shared_ptr
注意事项
- 避免循环引用的现象出现。可使用weak_ptr来进行解决。
基本用法
接口 |
返回值 |
说明 |
get() |
原始指针类型 |
获取智能指针管理的原始指针类型 |
reset() |
无 |
释放资源并将指针置空,或释放原始资源(引用计数-1)然后接管新资源 |
use_count() |
整形值 |
返回原始指针的引用计数 |
swap() |
无 |
交换两个指针的所有权 |
std::shared_ptr<MyClass> pSharedPtr1;
std::cout << "pSharedPtr1 address = " << std::hex << pSharedPtr1.get() << std::endl;
std::shared_ptr<MyClass> pSharedPtr2 = std::make_shared<MyClass>("make_shared pointer");
std::cout << "pSharedPtr2 address = " << std::hex << pSharedPtr2.get() << std::endl;
std::shared_ptr<MyClass> pSharedPtr3(new MyClass("use new create pointer"));
std::cout << "pSharedPtr3 address = " << std::hex << pSharedPtr3.get() << std::endl;
std::cout << "pSharedPtr3 use_count = " << pSharedPtr3.use_count() << std::endl;
std::shared_ptr<MyClass> pSharedPtr4(pSharedPtr3);
std::cout << "pSharedPtr4 address = " << std::hex << pSharedPtr4.get() << std::endl;
std::cout << "pSharedPtr4 use_count = " << pSharedPtr4.use_count() << std::endl;
std::shared_ptr<MyClass> pSharedPtr5 = pSharedPtr4;
std::cout << "pSharedPtr5 address = " << std::hex << pSharedPtr5.get() << std::endl;
std::cout << "pSharedPtr5 use_count = " << pSharedPtr5.use_count() << std::endl;
std::shared_ptr<MyClass> pSharedPtr6(std::move(pSharedPtr5));
std::cout << "pSharedPtr6 address = " << std::hex << pSharedPtr6.get() << std::endl;
std::cout << "pSharedPtr6 use_count = " << pSharedPtr6.use_count() << std::endl;
std::shared_ptr<MyClass> pSharedPtr7 = std::move(pSharedPtr6);
std::cout << "pSharedPtr7 address = " << std::hex << pSharedPtr7.get() << std::endl;
std::cout << "pSharedPtr7 use_count = " << pSharedPtr7.use_count() << std::endl;
(*pSharedPtr7).setName("use * dereference");
pSharedPtr7->doSomething();
if (pSharedPtr1)
{
std::cout << "pSharedPtr1 is not null!" << std::endl;
}
else
{
std::cout << "pSharedPtr1 is null!" << std::endl;
}
pSharedPtr2.swap(pSharedPtr7);
std::cout << "pSharedPtr2 address = " << std::hex << pSharedPtr2.get() << std::endl;
std::cout << "pSharedPtr2 use_count = " << pSharedPtr2.use_count() << std::endl;
std::cout << "pSharedPtr7 address = " << std::hex << pSharedPtr7.get() << std::endl;
std::cout << "pSharedPtr7 use_count = " << pSharedPtr7.use_count() << std::endl;
pSharedPtr7.reset(new MyClass("swap"));
std::cout << "pSharedPtr7 address = " << std::hex << pSharedPtr7.get() << std::endl;
std::cout << "pSharedPtr7 use_count = " << pSharedPtr7.use_count() << std::endl;
使用场景
- 作为函数局部变量(最常用)
函数内或局部作用域中使用,在离开作用域后会自动释放资源,有效避免资源泄露
int main()
{
{
std::shared_ptr<MyClass> pTemp = std::make_shared<MyClass>("temp pointer");
pTemp->doSomething();
}
std::cout<< "pTemp have been released" << std::endl;
return 0;
}
- 作为函数参数按值传递
void passByValue(std::shared_ptr<MyClass> ptr)
{
std::cout << "ptr address = " << std::hex << ptr.get() << std::endl;
std::cout << "ptr use_count = " << ptr.use_count() << std::endl;
ptr->doSomething();
ptr->setName("func pass by value");
}
int main()
{
std::shared_ptr<MyClass> pSharedPtr(new MyClass("pass by value"));
std::cout << "pSharedPtr address = " << std::hex << pSharedPtr.get() << std::endl;
std::cout << "pSharedPtr use_count = " << pSharedPtr.use_count() << std::endl;
passByValue(pSharedPtr);
std::cout << "pSharedPtr address = " << std::hex << pSharedPtr.get() << std::endl;
std::cout << "pSharedPtr use_count = " << pSharedPtr.use_count() << std::endl;
return 0;
}
- 作为函数参数按引用传递
void passByReference(std::shared_ptr<MyClass> &ptr)
{
std::cout << "ptr address = " << std::hex << ptr.get() << std::endl;
std::cout << "ptr use_count = " << ptr.use_count() << std::endl;
ptr->doSomething();
ptr->setName("func pass by reference");
}
int main()
{
std::shared_ptr<MyClass> pSharedPtr(new MyClass("pass by reference"));
std::cout << "pSharedPtr address = " << std::hex << pSharedPtr.get() << std::endl;
std::cout << "pSharedPtr use_count = " << pSharedPtr.use_count() << std::endl;
passByReference(pSharedPtr);
std::cout << "pSharedPtr address = " << std::hex << pSharedPtr.get() << std::endl;
std::cout << "pSharedPtr use_count = " << pSharedPtr.use_count() << std::endl;
return 0;
}
- 作为函数返回值
std::shared_ptr<MyClass> getSharedPtr()
{
std::shared_ptr<MyClass> tmpPtr = std::make_shared<MyClass>("local shared pointer");
std::cout << "tmpPtr address = " << std::hex << tmpPtr.get() << std::endl;
std::cout << "tmpPtr use_count = " << tmpPtr.use_count() << std::endl;
return tmpPtr;
}
int main()
{
getSharedPtr()->doSomething();
std::cout << "getSharedPtr() address = " << std::hex << getSharedPtr().get() << std::endl;
std::cout << "getSharedPtr() use_count = " << getSharedPtr().use_count() << std::endl;
return 0;
}
weak_ptr
注意事项
- 不可以单独存在
- 不具有原始指针的内存所有权
- 不能使用->和*进行访问和解引用
- 主要应用于解决shared_ptr循环引用问题
基本用法
接口 |
返回值 |
说明 |
reset() |
无 |
释放资源并将指针置空 |
use_count() |
整形值 |
返回原始指针的引用计数 |
swap() |
无 |
交换两个指针的所有权 |
expired() |
布尔值 |
判断指针是否有效 |
lock() |
shared_ptr对象 |
将weak_ptr变化为shared_ptr |
std::weak_ptr<MyClass> pWeakPtr1;
std::cout << "pWeakPtr1 use_count = " << pWeakPtr1.use_count() << std::endl;
std::shared_ptr<MyClass> pSharedPtr1 = std::make_shared<MyClass>("shared");
std::weak_ptr<MyClass> pWeakPtr2(pSharedPtr1);
std::cout << "pWeakPtr2 use_count = " << pWeakPtr2.use_count() << std::endl;
std::weak_ptr<MyClass> pWeakPtr3(pWeakPtr2);
std::cout << "pWeakPtr3 use_count = " << pWeakPtr3.use_count() << std::endl;
std::weak_ptr<MyClass> pWeakPtr4 = pWeakPtr3;
std::cout << "pWeakPtr4 use_count = " << pWeakPtr4.use_count() << std::endl;
std::weak_ptr<MyClass> pWeakPtr5(std::move(pWeakPtr4));
std::cout << "pWeakPtr4 use_count = " << pWeakPtr4.use_count() << std::endl;
std::cout << "pWeakPtr5 use_count = " << pWeakPtr5.use_count() << std::endl;
std::weak_ptr<MyClass> pWeakPtr6 = std::move(pWeakPtr5);
std::cout << "pWeakPtr5 use_count = " << pWeakPtr5.use_count() << std::endl;
std::cout << "pWeakPtr6 use_count = " << pWeakPtr6.use_count() << std::endl;
pWeakPtr6.lock()->setName("lock()");
pWeakPtr6.lock()->doSomething();
pWeakPtr6.reset();
std::cout << "pWeakPtr6 use_count = " << pWeakPtr6.use_count() << std::endl;
if(pWeakPtr6.expired())
{
std::cout << "pWeakPtr6 is invalid!" << std::endl;
}
std::shared_ptr<MyClass> pSharedPtr2 = std::make_shared<MyClass>("swap");
std::weak_ptr<MyClass> pWeakPtr7(pSharedPtr2);
pWeakPtr7.swap(pWeakPtr2);
pWeakPtr7.lock()->doSomething();
pWeakPtr2.lock()->doSomething();
使用场景
- 解决shared_ptr循环引用问题
int main()
{
std::shared_ptr<MyClass> pSharedPtr3 = std::make_shared<MyClass>("object03");
std::shared_ptr<MyClass> pSharedPtr4 = std::make_shared<MyClass>("object04");
pSharedPtr3->setFriend(pSharedPtr4);
pSharedPtr4->setFriend(pSharedPtr3);
return 0;
}