a review at smart pointer (1)
ref MSDN
在现代C++编程中,标准库,包含了smart pointer,使得开发者确保程序没有内存(资源)泄漏和exception-safe。
智能指针,定义在std命名空间的memory头文件里的,它们是raii的关键(资源获取即初始化)。raii的主要目的是对象的初始化和资源的获取在同一时刻进行,所以所有对象的资源的创建是一行代码就解决的。raii的原则是给所有堆初始化的资源以所有权,比如:动态分配的内存或者系统对象的句柄和在stack上分配的对象,其析构函数包含有delete函数和free函数的代码。
大多数情况下,当你初始化一个raw pointer或者资源句柄去指向一个真的资源时,请立刻停止并改使智能指针。在现代C++中,裸指针仅仅被用于小型代码区、块、极端的性能优化(没有办法用智能指针的时候)
void UseRawPointer()
{
// Using a raw pointer -- not recommended.
Song* pSong = new Song(L"Nothing on You", L"Bruno Mars");
// Use pSong...
// Don't forget to delete!
delete pSong;
}
void UseSmartPointer()
{
// Declare a smart pointer on stack and pass it the raw pointer.
unique_ptr<Song> song2(new Song(L"Nothing on You", L"Bruno Mars"));
// Use song2...
wstring s = song2->duration_;
//...
} // song2 is deleted automatically here.
如上述例子,smart pointer是stack上的class template,用raw pointer初始化,这个raw pointer指向堆内存的对象。智能指针初始化后,它就有了这个raw pointer的所有权。这表示,smart pointer负责析构raw pointer指向的那个内存。智能指针的析构函数包含了delete的调用,因为智能指针在stack上被声明,它的析构函数在其脱离其作用域时会被自动调用,even if an exception is thrown somewhere further up the stack.(不知道怎么理解)
访问这种封装好的指针要用->操作符,which,智能指针类重载了->然后返回了被封装的raw pointer。
C++智能指针类似于C#中对象的创建习惯,创建一个对象然后让系统take care of its deleting at the correct time,区别是,C++无在后台跑的GC,内存是由作用域管理的,更快。
记住永远不要用parameter list来初始化智能指针,智能指针永远“单独创建一行”(不理解parameter list是那个list)
Always create smart pointers on a separate line of code, never in a parameter list, so that a subtle resource leak won't occur due to certain parameter list allocation rules.
class LargeObject
{
public:
void DoSomething(){}
};
void ProcessLargeObject(const LargeObject& lo){}
void SmartPointerDemo()
{
// Create the object and pass it to a smart pointer
std::unique_ptr<LargeObject> pLarge(new LargeObject());
//Call a method on the object
pLarge->DoSomething();
// Pass a reference to a method.
ProcessLargeObject(*pLarge);
} //pLarge is deleted automatically when function block goes out of scope.
(综上我们可以看出,它传参传的是智能指针的const引用)
此例解释了如何使用智能指针
声明此指针为局部变量而不是用new或者malloc
在<>里规定封装指针指向的类型
在构造函数里放入裸指针的新对象
用重载操作符*或者->
智能指针基本和裸指针差不多大,四个字节或者八个,性能也是
智能指针自己的的成员函数要用"dot"来访问
在变量离开作用域之前,有些智能指针可以用reset释放所有权来free memory,如下:
void SmartPointerDemo2()
{
// Create the object and pass it to a smart pointer
std::unique_ptr<LargeObject> pLarge(new LargeObject());
//Call a method on the object
pLarge->DoSomething();
// Free the memory before we exit function block.
pLarge.reset();
// Do some other work...
}
Smart pointers usually provide a way to access their raw pointer directly. C++ Standard Library smart pointers have a get member function for this purpose, and CComPtr has a public p class member. By providing direct access to the underlying pointer, you can use the smart pointer to manage memory in your own code and still pass the raw pointer to code that does not support smart pointers.(大概是有一个get()方法可以拿到裸指针,然后CComPtr估计是MS黑魔法)
void SmartPointerDemo4()
{
// Create the object and pass it to a smart pointer
std::unique_ptr<LargeObject> pLarge(new LargeObject());
//Call a method on the object
pLarge->DoSomething();
// Pass raw pointer to a legacy API
LegacyLargeObjectFunction(pLarge.get());
}
C++ Standard Library smart pointers
-
unique_ptr
允许指针有又一个所有权,用unique ptr作为首选,除非你知道你确定要用shared ptr。unique ptr的所有权可以被移给一个新的owner,但是不能copied or shared。shared ptr旨在替换废弃的auto ptr,unique ptr比boost库的scoped ptr要好,它的尺寸仅占一个指针的位置且支持右值引用(为了插入删除获取快一些) -
shared_ptr
引用计数的指针,Use when you want to assign one raw pointer to multiple owners,用这个,比如当返回一个指针的copy的时候(并保留原来的),这个时候,就要用shared ptr,此指针不会被删除,直到它的shared_ptr离开作用域之外,它的尺寸是两个指针大小,第一块是为了储存那个对象,第二块是shared control block,包含引用计数。 -
weak_ptr
和shared ptr搭配的指针,一个weak ptr给一个被多个shared ptr指针指向的对象提供访问的通道,但是并不参与reference counting,不翻译了,翻译不明白。
Special-case smart pointer for use in conjunction withshared_ptr. Aweak_ptrprovides access to an object that is owned by one or moreshared_ptrinstances, but does not participate in reference counting. Use when you want to observe an object, but do not require it to remain alive. Required in some cases to break circular references betweenshared_ptrinstances. Header file:<memory>. For more information, see How to: Create and Use weak_ptr Instances and weak_ptr Class.
How to: Create and use unique_ptr instances
- 这个例子展示了什么叫做用move来转移所有权,而不是将指针assign给另一个指针。
unique_ptr<Song> SongFactory(const std::wstring& artist, const std::wstring& title)
{
// Implicit move operation into the variable that stores the result.
return make_unique<Song>(artist, title);
}
void MakeSongs()
{
// Create a new unique_ptr with a new object.
auto song = make_unique<Song>(L"Mr. Children", L"Namonaki Uta");
// Use the unique_ptr.
vector<wstring> titles = { song->title };
// Move raw pointer from one unique_ptr to another.
unique_ptr<Song> song2 = std::move(song);
// Obtain unique_ptr from function that returns by value.
auto song3 = SongFactory(L"Michael Jackson", L"Beat It");
}
void SongVector()
{
vector<unique_ptr<Song>> songs;
// Create a few new unique_ptr<Song> instances
// and add them to vector using implicit move semantics.
songs.push_back(make_unique<Song>(L"B'z", L"Juice"));
songs.push_back(make_unique<Song>(L"Namie Amuro", L"Funky Town"));
songs.push_back(make_unique<Song>(L"Kome Kome Club", L"Kimi ga Iru Dake de"));
songs.push_back(make_unique<Song>(L"Ayumi Hamasaki", L"Poker Face"));
// Pass by const reference when possible to avoid copying.
for (const auto& song : songs)
{
wcout << L"Artist: " << song->artist << L" Title: " << song->title << endl;
}
}
- 注意在循环里如果不用&会报错,因为unique_ptr的copy contructor是默认没有的
// Create a unique_ptr to an array of 5 integers.
auto p = make_unique<int[]>(5);
// Initialize the array.
for (int i = 0; i < 5; ++i)
{
p[i] = i;
wcout << p[i] << endl;
}
- 上述例子给int*(int[])做了一个智能指针,五个单位长度的数组,我们可以看出,初始化一个智能指针<>里可以放一个类,然后用new关键字在后面(代表一个这个类一个智能指针),还有另外一种就是<>里放一个数组,然后()里放你要几个长度的数组,访问这个指针可以用array[i]这样访问,也就是说智能指针给数组单独做了一套机制。
浙公网安备 33010602011771号