auto_ptr,
可以联想 c的alloca()。alloca和auto_ptr只有自动释放的共性。
p40
a. auto_ptr 是這樣一種指標:它是「它所指向的物件」的擁有者(owner)。
auto_ptr 要求,一
個物件只能有一個擁有者,嚴禁一物二主。
无论何种情况下,auto_ptr被销毁,就一定连带释放其所指资源。
c.
絕對不應
該出現多個auto_ptrs 同時擁有一個物件的情況。不幸的是,這種事情可能會發
生
(如果你以同一個物件為初值,將兩個 auto_ptr s 初始化,就會出現這種事)。
程式員必須負責防範這種錯誤。
d.
auto_ptr 的copy 建構式和
assignment運算子將物件擁有權交出去。
擁
有者一旦交出擁有
權,就兩手空空,只剩一個null指標在手了。
//注意
e. 使用auto_ptr,要清楚是否需要交接拥有权和拥有权交接点。
f. auto_ptr 的語義本身就涵蓋擁有權,所以如果你無意轉交你的擁有權,就不要在
參數列中使用auto_ptr ,也不要以它作爲回返值。
//bad example
std::auto_ptr<int> p(new int);
*p = 42; // change value to which p refers
bad_print(p); // Oops, deletes the memory to which p refers
*p = 18; // RUNTIME ERROR
const
std::auto_ptr<int> p(new int);
//p44
總而言之,常數型auto_ptr 減小了「不經意轉移擁有權」所帶來的危險。只要一
個物件藉由auto_ptr 傳遞,就可以使用常數型auto_ptr
來終結擁有權移轉鏈,
此後擁有權將不能再進行移轉。
關鍵字const 並非意味你不能更改auto_ptr 所擁有的物件,而是意味
你不能更改auto_ptr 的擁有權。
g.
將auto_ptr s 以pass by reference 方式傳遞就萬事大吉。然而這
種行爲卻會使「擁有權」的概念變得難以捉摸,因爲面對一個「透過reference 而
獲得auto_ptr 」的函式,你根本無法預知擁有權是否被轉交。所以以 by reference
方式傳遞auto_ptr 是非常糟糕的設計,應該全力避免。
p46 auto_ptr的4个错误运用,详见原文。
autoptr.hpp
/* The following code example is taken from the book
* "The C++ Standard Library - A Tutorial and Reference"
* by Nicolai M. Josuttis, Addison-Wesley, 1999
*
* (C) Copyright Nicolai M. Josuttis 1999.
* Permission to copy, use, modify, sell and distribute this software
* is granted provided this copyright notice appears in all copies.
* This software is provided "as is" without express or implied
* warranty, and with no claim as to its suitability for any purpose.
*/
/* class auto_ptr
* - improved standard conforming implementation
*/
namespace std {
// auxiliary type to enable copies and assignments (now global)
template<class Y>
struct auto_ptr_ref {
Y* yp;
auto_ptr_ref (Y* rhs)
: yp(rhs) {
}
};
template<class T>
class auto_ptr {
private:
T* ap; // refers to the actual owned object (if any)
public:
typedef T element_type;
// constructor
explicit auto_ptr (T* ptr = 0) throw()
: ap(ptr) {
cout << "explicit auto_ptr() excute..." << endl;
if(ptr)
{
cout << "explicit auto_ptr() *ap:" << *ptr << endl;
}
}
// copy constructors (with implicit conversion)
// - note: nonconstant parameter
auto_ptr (auto_ptr& rhs) throw()
: ap(rhs.release()) {
cout << "auto_ptr (auto_ptr& rhs) excute..." << endl;
}
template<class Y>
auto_ptr (auto_ptr<Y>& rhs) throw()
: ap(rhs.release()) {
cout << "auto_ptr (auto_ptr<Y>& rhs) excute..." << endl;
}
// assignments (with implicit conversion)
// - note: nonconstant parameter
auto_ptr& operator= (auto_ptr& rhs) throw() {
cout << "operator= (auto_ptr& rhs) excute..." << endl;
reset(rhs.release());
return *this;
}
template<class Y>
auto_ptr& operator= (auto_ptr<Y>& rhs) throw() {
cout << "operator= (auto_ptr<Y>& rhs) excute..." << endl;
reset(rhs.release());
return *this;
}
// destructor
~auto_ptr() throw() {
delete ap;
}
// value access
T* get() const throw() {
return ap;
}
T& operator*() const throw() {
cout << "operator*() excute..." << endl;
return *ap;
}
T* operator->() const throw() {
return ap;
}
// release ownership
T* release() throw() {
T* tmp(ap);
ap = 0;
return tmp;
}
// reset value
void reset (T* ptr=0) throw() {
if (ap != ptr) {
delete ap;
ap = ptr;
}
}
/* special conversions with auxiliary type to enable copies and assignments
*/
auto_ptr(auto_ptr_ref<T> rhs) throw()
: ap(rhs.yp) {
cout << "auto_ptr(auto_ptr_ref<T> rhs) excute..." << endl;
}
auto_ptr& operator= (auto_ptr_ref<T> rhs) throw() { // new
reset(rhs.yp);
return *this;
}
template<class Y>
operator auto_ptr_ref<Y>() throw() {
return auto_ptr_ref<Y>(release());
}
template<class Y>
operator auto_ptr<Y>() throw() {
return auto_ptr<Y>(release());
}
};
}
main.cpp
/* The following code example is taken from the book
* "The C++ Standard Library - A Tutorial and Reference"
* by Nicolai M. Josuttis, Addison-Wesley, 1999
*
* (C) Copyright Nicolai M. Josuttis 1999.
* Permission to copy, use, modify, sell and distribute this software
* is granted provided this copyright notice appears in all copies.
* This software is provided "as is" without express or implied
* warranty, and with no claim as to its suitability for any purpose.
*/
#include <iostream>
//#include <memory>
#include "autoptr.hpp"
using namespace std;
/* define output operator for auto_ptr
* - print object value or NULL
*/
#if 0
//test 1,允许转移,且有转移
ostream& operator<< (ostream& strm, auto_ptr<T>& p)
{
......
auto_ptr<T> tmp = p;
}
//test 2,不允许转移,但有转移
ostream& operator<< (ostream& strm, const auto_ptr<T>& p)
{
......
auto_ptr<T> tmp = p;
}
#endif
template <class T>
ostream& operator<< (ostream& strm, const auto_ptr<T>& p)
{
// does p own an object ?
if (p.get() == NULL) {
strm << "NULL"; // NO: print NULL
}
else {
strm << *p; // YES: print the object
}
//auto_ptr<T> tmp = p;
return strm;
}
int main()
{
auto_ptr<int> r(new int(43));
auto_ptr<int> s = r; //copy constructor
cout << "##############" << endl << endl;
auto_ptr<int> p(new int(42));
auto_ptr<int> q;
cout << "after initialization:" << endl;
cout << " p: " << p << endl;
cout << " q: " << q << endl;
q = p;
cout << "after assigning auto pointers:" << endl;
cout << " p: " << p << endl;
cout << " q: " << q << endl;
*q += 13; // change value of the object q owns
p = q;
cout << "after change and reassignment:" << endl;
cout << " p: " << p << endl;
cout << " q: " << q << endl;
}