本文主要講述Visual C++,怎樣創建Visual C++項目。如何編制Visual C++的代碼,這些內容都是一些門戶網站和技術論壇找到的,中間可能有不少錯誤是我沒有挑出的,歡迎大家指正。
它將指針包裝成了類,並且重載了反引用(dereference)運算符operator *和成員選擇運算符operator ->,以模仿指針的行為。關於auto_ptr<>的具體細節,參閱《The C++ Standard Library》(中譯本:C++標准庫)。
例如以下Visual C++代碼,
- #include < cstring >
- #include < memory >
- #include < iostream >
- class string
- {
- public:
- string(const char* cstr) { _data=new char [ strlen(cstr)+1 ]; strcpy(_data, cstr); }
- ~string() { delete [] _data; }
- const char* c_str() const { return _data; }
- private:
- char* _data;
- };
- void foo()
- {
由於str是函數的局部對象,因此在函數退出點生存期結束,此時auto_ptr<string>的析構函數調用,自動銷毀內部指針維護的string對象(先前在構造函數中通過new表達式分配而來的),並進而執行string的析構函數,釋放為實際的字符串動態申請的內存。在string中也可能管理其他類型的資源,如用於多線程環境下的同步資源。下圖說明了上面的過程。
- auto_ptr < string > str1( new string( < str1 > ) );
- cout << str1->c_str();
- auto_ptr < string > str2(str1); // str1內部指針不再指向原來的對象
- cout << str2->c_str();
- cout << str1->c_str(); // 未定義,str1內部指針不再有效
現在我們擁有了最簡單的廢料收集機制(我隱瞞了一點,在string中,你仍然需要自己編碼控制對象的動態創建和銷毀,但是這種情況下的准則極其簡單,就是在構造函數中分配資源,在析構函數中釋放資源,就好像飛機駕駛員必須在起飛後和降落前檢查起落架一樣。),即使在foo函數中發生了異常,str的生存期也會結束,C++保證自然退出時發生的一切在異常發生時一樣會有效。
auto_ptr<>只是智能指針的一種,它的復制行為提供了所有權轉移的語義,即智能指針在復制時將對內部維護的實際指針的所有權進行了轉移,例如:
- template < typename T >
- class shared_ptr
- {
- private:
- class implement // 實現類,引用計數
- {
- public:
- implement(T* pp):p(pp),refs(1){}
- ~implement(){delete p;}
- T* p; // 實際指針
- size_t refs; // 引用計數
- };
- implement* _impl;
- public:
- explicit shared_ptr(T* p)
- : _impl(new implement(p)){}
- ~shared_ptr()
- {
- decrease(); // 計數遞減
- }
- shared_ptr(const shared_ptr& rhs)
- : _impl(rhs._impl)
- {
- increase(); // 計數遞增
- }
某些時候,需要共享同一個對象,此時auto_ptr就不敷使用,由於某些歷史的原因,Visual C++的標准庫中並沒有提供其他形式的智能指針,走投無路了嗎?在main()函數中,先調用foo1(val),函數中使用了一個局部對象temp,它和val共享同一份數據,並修改了實際值。
函數返回後,val擁有的值同樣也發生了變化,而實際上val本身並沒有修改過。然後調用了foo2(val),函數中使用了一個無名的臨時對象創建了一個新值,使用賦值表達式修改了val,同時val和臨時對象擁有同一個值,函數返回時,val仍然擁有這正確的值。