程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 對auto_ptr的學習

對auto_ptr的學習

編輯:關於C++

auto_ptr是C++標准庫提供的類模板,它可以幫助程序員自動管理用new表達式動態分配的單個對象,不過對用new表達式分配的數組管理沒有類似的支持,不能用auto_ptr存儲數組,如果這樣做了,結果將是未定義的.

auto_ptr對象被初始化為指向由new表達式創建的動態分配對象.當auto_ptr對象的生命期結束時,動態分配的對象被自動釋放.

在使用auto_ptr類模板之前,必須包含下面的頭文件:

#include <memory>

auto_ptr對象的定義有下面三種形式:

  auto_ptr<type_pointed_to> identifier(ptr_allocated_by_new);
  auto_ptr<type_pointed_to> identifier(auto_ptr_of_same_type);
  auto_ptr<type_pointed_to> identifier;

type_pointed_to代表由new表達式創建的對象的類型.在最常見的情況下,我們希望把auto_ptr直接初始化為new表達式返回的對象地址.可以這樣來做:

auto_ptr<int> pi(new int(1024);

pi被初始化為由new表達式創建的對象的地址,且該對象的初始化值為1024.可以檢查auto_ptr所指的對象的值,方式與普通指針相同:

if (*pi != 1024);

new表達式創建的對象由pi指向,當pi的生命期結束時,它將被自動釋放.如果pi是全局對象,則pi所指向的對象在程序結束時釋放.

如果我們用一個class類型的對象初始化auto_ptr對象,比如標准的string類型,則:

auto_ptr<string> pstr_auto(new string("Hello world"));

假設現在希望訪問一個字符串操作,對於普通的string指針,會按照下面這樣來做:

string* pstr_type = new string("Hello World");

pstr_type->size();

那麼,用auto_ptr也是一樣的方式:

auto_ptr<string> pstr_auto(new string("Hello world"));

pstr_auto->size();

auto_ptr類模板背後的主要動機是支持與普通指針類型相同的語法,但是為auto_ptr對象所指對象的釋放提供自動管理.同時,使用auto_ptr對象並不比直接使用指針代價更高.

在下面的情況中,用pstr_auto的值初始化pstr_auto2,並且pstr_auto的底層對象是string,會怎樣呢?

auto_ptr<string> pstr_auto2(pstr_auto);

假定直接用一個string指針初始化另外一個,比如:

string* pstr_type2(pstr_type);

那麼,這兩個指針都持有程序空閒存儲區內的字符串地址,我們必須小心地將delete表達式只應用在一個指針上,而auto_ptr類模擬支持所有權概念.

當定義auto_ptr時,它知道自己對初始化字符串擁有所有權,並且有責任刪除該字符串,這是所有權授予auto_ptr對象的責任.

問題是,當pstr_auto2被初始化為指向與pstr_auto相同的對象時,所有權會發生什麼樣的變化?我們不希望讓兩個auto_ptr對象都擁有同一個底層對象--這會引起重復刪除對象的問題,這也是我們使用auto_ptr類型首先要防止的.

當一個auto_ptr對象被用另一個auto_ptr對象初始化或賦值時,左邊被賦值或初始化的對象就擁有了空閒存儲區內底層對象的所有權,而右邊的auto_ptr對象則撤消所有責任.於是,在我們的例子中,將是用pstr_auto2刪除字符串對象,而不是pstr_auto,pstr_auto不再被用來指向字符串對象.

類似的行為也發生在賦值操作符上,已知下列兩個auto_ptr對象.

auto_ptr<int> p1(new int(1024));

auto_ptr<int> p2(new int(2048));

賦值操作符可以將一個auto_ptr對象拷貝到另一個中,如下所示:

p1 = p2;

在賦值之前,由p1指向的對象被刪除.賦值之後,p1擁有int型對象的所有權,該對象值為2048,p2不再被用來指向該對象.

在auto_ptr定義的第三種形式中,我們創建一個auto_ptr對象,但是沒有用指針將其初始化.例如:

auto_ptr<int> p_auto_int;

因為p_auto_int沒有被初始化指向一個對象,所以它的內部指針值被設置為0,這意味著對它解引用會使程序出現未定義的行為,就好像我們直接解引用一個值為0的指針時所發生的一樣.

對於普通指針,我們只需測試是否為0,例如:

if (pi != 0);

但是怎樣測試一個auto_ptr對象是否指向一個底層對象呢?操作get()返回auto_ptr對象內部的底層指針,所以為了判斷auto_ptr指針是否指向一個對象,可以如下編程:

  int *pi = 0;
  if (p_auto_int.get() != 0 && *p_auto_int != 1024)
  *p_auto_int = 1024;

如果它沒有指向一個對象,那麼怎樣使其指向一個呢?即怎樣設置一個auto_ptr對象的底層指針?我們可以用reset()操作,例如:

p_auto_int.reset(new int(1024));

我們不能夠在auto_ptr對象被定義之後,再用new表達式創建對象的地址來直接向其賦值,因此,我們不能這樣寫:

  void example()
  {
  auto_ptr<int> pi;
  {
  pi = new int(4);
  }
  }

如果為了重置一個auto_ptr對象,我們必須使用reset()函數,我們可以向reset()傳遞一個指針,如果不希望設置該auto_ptr對象的話,可以傳遞一個0值.如果auto_ptr當前指向一個對象並且該auto_ptr對象擁有該對象的所有權,則該對象在底層指針被重置之前,首先被刪除,例如:

auto_ptr<string> pstr_auto(new string("Hello World"));

pstr_auto.reset(new string("YES")); //在重置之前刪除對象Hello World

在這種情況下,用字符串操作assign()對原有的字符串對象重新賦值,比刪除原有的字符串對象並重新分配第二個字符串對象更為有效:

//這種情況下,重置的更有效

pstr_auto->assign("YES");

程序設計的一個難事是:有時候僅僅得到正確的結果是不夠的,有時候,我們不僅需要正確的結果,而且還需要一個可接受的性能,像調用assign()有效釋放和重分配一個字符串這樣的小細節就是一個很好的例子,它說明在某些情況下,這些小細節會積聚成可怕的性能瓶頸.

auto_ptr類模板為動態分配內存提供了大量的安全性和便利性,但是我們仍需小心,否則就會陷入麻煩.

1.我們必須小心,不能用一個指向"內存不是通過應用new表達式分配的"指針來初始化或賦值auto_ptr.如果這樣做了,delete表達式會被應用在不是動態分配的指針上,這將導致未定義的程序行為.

2.我們必須小心,不能讓兩個auto_ptr對象擁有空間存儲區內同一對象的所有權.一種很顯然犯這種錯誤的方法是,用同一個指針初始化或賦值兩個auto_ptr對象,另一個途徑是通過get()操作,例如:

auto_ptr<string> pstr_auto(new string("HELLO"));

auto_ptr<string> pstr_auto2(pstr_auto.get());

release()操作允許將一個auto_ptr對象的底層對象初始化或賦值給第二個對象,而不會使兩個auto_ptr對象同時擁有同一個對象的所有權.release(0不權像get()一樣返回底層對象的地址,而且還釋放該對象的所有權,前面代碼可被改寫如下:

auto_ptr<string> pstr_auto2(pstr_auto.release());

此時兩個對象仍然指向同一個對象,但是pstr_auto不再擁有擁有權.

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved