详解请参照
智能指针详解
本文主要依据C++ primer的基础知识分析智能指针,并最后给出智能指针的实现;
shared_ptr
- shared_ptr允许多个指针指向同一个对象
- shared_ptr是实现为模板,当创建一个智能指针时,必须提供额外的信息—-指针可以指向的类型;
-
最安全的分配和使用动态内存的方法是调用一个名为make_shared的标准库函数,此函数在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr;
-
shared_pre<int> p = make_shared<int>(42);
- shared_ptr的析构函数会递减它所指向的对象的引用计数,如果引用计数变为0,shared_ptr的析构函数就会销毁对象,并释放它所占用的内存;
- shared_ptr在无用之后仍然保留的一种可能是,将shared_ptr存放在一个容器中,随后重排了容器,从而不再需要某些元素,在此情况下,应该确保用erase删除那些不再需要的shared_ptr元素;
-
直接管理内存
-
默认情况下,动态分配的对象是默认初始化的,这意味着内置类型或组合类型的对象将是未定义的,而类类型对象将用默认构造函数进行初始化;
- 值初始化的内置类型对象有着良好定义的值,而默认初始化的对象的值则是未定义的;
- 用new分配const 对象是合法的,一个动态分配的const 对象必须进行初始化,想要释放一个const 动态对象,只要delete 指向它的指针即可;
- 由内置指针(而不是智能指针)管理的内存在被显式释放前一直都会存在;
-
使用new和delete管理动态内存存在三个常见问题:
- 忘记delete内存;
- 使用已释放掉的对象;
- 同一块内存释放两次;
- 动态内存的一个基本问题是可能有多个指针指向相同的内存,在delete 内存之后重置指针的方法只对这个指针有效,对其他任何仍指向(已释放的)内存的指针是无作用的;
shared_ptr和new结合使用
-
可以用new返回的指针初始化智能指针,
必须使用直接初始化的形式初始化一个智能指针:
-
shared_ptr<int> p(new int(1024));
- 一个用来初始化智能指针的普通指针必须指向动态内存;
-
当将一个shared_ptr 绑定到一个普通指针时,就将内存的管理责任交给了这个shared_ptr,一旦这样做了,就不应该再使用内置指针来访问来访问这个shared_ptr 所指向的内存;
- 使用内置指针访问一个智能指针所负责的对象是很危险的,因为我们无法知道对象何时被销毁;
-
get用来将指针的访问权限传递给代码,
只有在确定代码不会delete指针的情况下才能使用get。特别是,永远不要用get初始化另一个智能指针或为另一个智能指针赋值;
-
-
智能指针可以提供对动态分配的内存安全又方便的管理,但这建立在正确使用的前提下,为了正确使用智能指针,必须坚持一些基本规范:
- 不使用相同的内置指针值初始化(或reset)多个智能指针;
- 不delete get()返回的指针;
- 不使用get() 初始化或reset 另一个智能指针;
- 如果使用get() 返回的指针,记住当最后一个对应的智能指针销毁后,你的指针就变为无效了;
- 如果你使用智能指针管理的资源不是new 分配的内存,记住传递给它一个删除器;
智能指针的简单实现:
#include<iostream>
using namespace std;
template<typename T>
class SmartPointer{
private:
T* ptr;
size_t* reference_count;
void releaseCount(){
if (ptr){
(*reference_count)--;
if ((*reference_count) == 0){
delete ptr;
delete reference_count;
}
}
}
public:
SmartPointer(T* p = 0) :ptr(p), reference_count(new size_t){
if (p)*reference_count = 1;
else *reference_count = 0;
}
SmartPointer(const SmartPointer& src){
if (this != &src){
ptr = src.ptr;
reference_count = src.reference_count;
(*reference_count)++;
}
}
SmartPointer& operator=(const SmartPointer& src){
if (ptr == src.ptr)return *this;
releaseCount();
ptr = src.ptr;
reference_count = src.reference_count;
(*reference_count)++;
return *this;
}
T* operator*(){
return (*ptr);
}
T* operator->(){
return ptr;
}
~SmartPointer(){
if (--(*reference_count) == 0){
delete ptr;
delete reference_count;
}
}
size_t get_reference(){
return *reference_count;
}
};
int main(){
SmartPointer<char> cp1(new char('a'));
cout << "cp1.reference_count = " << (cp1.get_reference()) << endl;
SmartPointer<char> cp2(cp1);
cout << "cp1.reference_count = " << (cp1.get_reference()) << endl;
cout << "cp2.reference_count = " << (cp2.get_reference()) << endl;
SmartPointer<char> cp3 = cp2;
cout << "cp2.reference_count = " << (cp2.get_reference()) << endl;
cp3 = cp1;
cout << "cp3.reference_count = " << (cp3.get_reference()) << endl;
cp3 = cp3;
SmartPointer<char> cp4(new char('b'));
cp3 = cp4;
cout << "cp4.reference_count = " << (cp4.get_reference()) << endl;
cout << "cp3.reference_count = " << (cp3.get_reference()) << endl;
cout << "cp2.reference_count = " << (cp2.get_reference()) << endl;
system("pause");
return 0;
}
unique_ptr
-
某个时刻只能有一个unique_ptr 指向一个给定对象,定义一个unique_ptr时,需要将其绑定到一个new 返回的指针上,初始化unique_ptr必须采用直接初始化形式;
- unique_ptr 不支持普通的拷贝或赋值操作;
- 可以通过release 或 reset将指针的所有权从一个(非const)unique_ptr转移给另一个unique_ptr;
- unique_ptr 默认情况下用delete 释放它所指向的对象,也可以提供一个指定类型的删除器;
版权声明:本文为u010150046原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。