天天看點

Effective C++讀書筆記(四)——資源管理資源管理

目錄

資源管理

1.以對象管理資源

2.在管理資源類中小心copying行為

3.在資源管理類中提供對原始資源的通路

4.成對使用new和delete時要采用相同形式

5.以獨立語句将newd對象置入智能指針

資源管理

1.以對象管理資源

中心思想:把資源放進對象内,便可以依賴C++的析構函數自動調用機制確定資源被釋放。

關鍵點:

1.獲得資源後立刻放進管理對象。(Resource Acquisition Is Initialization,RAII)

2.管理對象運用析構函數確定資源被釋放。

class Lock
{
public:
    explict Lock(Mutex* pm)
    : mutexPtr(pm)
    {
        lock(mutexPtr);
    }
    ~Lock()
    {
        unlock(mutexPtr);
    }
private:
    Mutex *mutexPtr;
}
           

注意事項:

1.為防止資源洩漏,請使用RAII對象,它們在構造函數中擷取資源并在析構函數中釋放資源。

2.兩個常被使用的RAII classes分别是share_ptr和auto_ptr,前者通常是較佳選擇。

2.在管理資源類中小心copying行為

如果RAII對象被複制,會發生什麼情況?

1. 禁止複制

通常允許RAII對象被複制不合理,如果需要禁止copy RAII對象,可以通過将copying操作聲明為private(繼承Uncopyable類)來禁止copy;

 2. 對底層資源使用引用計數法(reference-count)

如果需要保留資源直到資源的最後一個使用者被銷毀,可實作引用計數法(shared_ptr)。

class Lock
{
public:
    explict Lock(Mutex* pm)
    : mutexPtr(pm , unlock)
    {
        lock(mutexPtr.get());
    }
    ~Lock()
    {
        unlock(mutexPtr);
    }
private:
    std::tr1::shared_ptr<Mutex> mutexPtr;
}
           

std::tr1::shared_ptr允許指定删除器,當引用次數為0時調用。

3.在資源管理類中提供對原始資源的通路

#include <iostream>
#include <memory>

using namespace std;

class MyTest
{
public:
	MyTest()
	:n(0)
	{
		cout<<"MyTest()"<<endl;
	}
	~MyTest()
	{
		cout<<"~MyTest()"<<endl;
	}
	MyTest(const MyTest& m)
	{
		cout<<"copying MyTest"<<endl;
		this->n = m.n;
	}
	void printMyTest(MyTest* m)
	{
		cout<<"printMyTest "<<m->n<<endl;
	}
private:
	int n;
};


int main()
{
	//std::shared_ptr<MyTest> m_test = new MyTest();
	//error: conversion from ‘MyTest*’ to non-scalar type ‘std::shared_ptr<MyTest>’ requested

	std::shared_ptr<MyTest> m_test(new MyTest());
	m_test->printMyTest(m_test.get());
	
    //m_test->printMyTest(m_test);
	//error: cannot convert ‘std::shared_ptr<MyTest>’ to ‘MyTest*’ ,通過get方法擷取raw指針
	return 0;
}

——————————————————————————————————————————————————————————————————————
[[email protected] 15]# ./main
MyTest()
printMyTest 0
~MyTest()
           

4.成對使用new和delete時要采用相同形式

被删除的指針對象,是單一對象或是對象數組,處理方式不同,對象資料記憶體布局裡會多存儲一個記錄n,表示數組的大小。

(備注:不要對數組形式做typedef操作,容易産生誤操作)

std::string* mystr = new std::string();
std::string* mystrArr = new std::string[100];

delete mystr;
delete [] mystrArr;


typedef std::string strArr[10];
std::string* str = new strArr;

delete str;//出錯
delete [] str;//正确
           

5.以獨立語句将newd對象置入智能指針

processWidget(std::shared_ptr<Widget>(new Widget), priority());
調用processWidget需要經曆以下三個步驟:
1.調用priority()函數;
2.執行 new Widget
3.調用std::shared_ptr構造函數

C++編譯器以什麼樣的次序完成上述三個步驟存在彈性。如果執行順序是213,然後在調用priority的過程中出現異常,那new Widget傳回的指針将會遺失,不會存入std::shared_ptr内。
即資源建立和資源被轉換為資源管理對象過程中,可能發生異常幹擾。是以建議将上述函數調用改為:
std::shared_ptr<Widget> pw(new Widget)
processWidget(pw,priority());
           

繼續閱讀