關於auto ptr ref的一點問題

2021-05-25 07:47:45 字數 3384 閱讀 7291

(略微修改了格式和錯別字)

今天我在看《

the c++ standard library

》的時候,總覺的上面講的關於

auto_ptr_ref

的問題沒有說清楚,查了網上的資料發現也沒有說清。

也許還有很多朋友像我一樣對此存在疑問。其實,這個問題有沒有弄清楚,對實際程式設計影響並不大,但是本著「勿在浮沙築高台」的精神,我用了乙個晚上的時間,來個徹底的大調查,終於基本上弄明白了其中的道理。(大多數時間都浪費在

vc上,因為

vc支援對右值的

non-const reference

,而標準

c++不可以,所以在

vc中,有沒有

auto_ptr_ref

實際上都無所謂!)

stl中有乙個智慧型指標

auto_ptr

,可以實現簡單的記憶體自動**,防止記憶體洩漏

(memory leakage)

。auto_ptr

實際是乙個類,在該類析構時自動呼叫

delete

,從而達到了記憶體**的效果。

但是,由於同乙個指標同一時刻只能被乙個

auto_ptr

占用,如果採用賦值操作(

=)或者拷貝構造函式呼叫等,就會發生所有權轉移,例如:

auto_ptrp(new int(0));

auto_ptrq; 此時

,p擁有指向乙個

int的指標,

q的指標為空。如果執行

q=p;

則,p指向空,q指向

int;

但是,這樣所有權轉換的問題同樣發生在引數傳遞中,例如

void foo(auto_ptrt);

如果呼叫

foo(p); 那麼p

就丟失了指標,所以乙個解決方法是用引用 例如

void foo1

(auto_ptr& t);

void foo2 (const auto_ptr& t);

兩者都是可以的,不過

foo1

非常不安全,因為在函式裡面很容易通過類似賦值的操作使

t丟失指標,而

foo2

不會。

例如:void foo2(const auto_ptr& t)

會發生編譯錯誤,從而避免災難的發生。但隨之又出現乙個很大的問題,就是

auto_ptr

類的拷貝建構函式,或者賦值函式。

最理想的情況是這樣

(如果能成功,就不會有別的什麼問題):

auto_ptr(const auto_ptr& rhs):ap(rhs.release()){}

但由於上述的原因,會發生編譯錯誤(因為呼叫了

release(),

而release()

會改變成員變數,不再是

const)

。所以只能去掉

const,

變為:

auto_ptr(auto_ptr& rhs):ap(rhs.release()){}

這樣可以編譯成功,而且往往也能正確執行,但是唯一的問題是: 當

rhs為右值時會出現問題。為了簡化問題,先假設拷貝建構函式什麼都不做,即:

auto_ptr(auto_ptr& rhs){}

那麼,如果有

auto_ptrp(new int(10)) 執行

auto_ptrq(p),

不會有任何問題,因為

p是左值。但如果執行

auto_ptrq(auto_ptr(new int(10)));

則會發生編譯錯誤,因為

auto_ptr(new int(10))

是右值,對右值的引用只能是常引用,也就是

"const auto_ptr& rhs"

的形式。但這裡要注意的是,剛才那段**用

vc編譯沒有任何問題,並且可以順利執行,但是用

gcc之類的標準

c++就不能順利編譯。 在

vc中auto_ptr& p=auto_ptr(new int(0));

是合法的,但在標準

c++中是不合法的,只有

const auto_ptr& p=auto_ptr(new int(0));

才是合法的,也即在標準

c++中,對右值的引用只能是

const

引用。所以說,要在標準

c++中實現

auto_ptrp(auto_ptr(new int(0)));

就變得不可能了,因為如上所說,拷貝建構函式是這樣的形式:

auto_ptr(auto_ptr& rhs):ap(rhs.release()){}

但是不能把右值傳到乙個非

常引用中。但畢竟有聰明的人能想到解決辦法,利用**類

( proxy class)。

宣告如下結構

,為了方便,我用

int代替模板引數

struct auto_ptr_ref

}; 然後在auto_ptr

類中增加了以下東東:

auto_ptr(auto_ptr_ref rhs):ap(rhs.p){}

auto_ptr& operator=(auto_ptr_ref rhs)

operator auto_ptr_ref()

之後,如果在標準

c++有以下呼叫(

vc中也會按照這個步驟呼叫,雖然沒有

auto_ptr_ref

它也能直接呼叫)

auto_ptrp(auto_ptr(new int(0)))

便可以成功,過程如下:

1. 構造臨時物件

auto_ptr(new int(0))

2. 想將臨時物件通過拷貝建構函式傳給

p,卻發現沒有合適的拷貝建構函式,因為只有

auto_ptr(auto_ptr& rhs

),這個又不能用,又沒有

auto_ptr(const auto_ptr& rhs)

(因為用了在所有權轉移中會出錯),呵呵!

3. 編譯器只能曲線救國,看看型別轉換後能不能傳遞。

4. 由於我們定義了

operator auto_ptr_ref()

所以編譯器自然就可以試一下轉為

auto_ptr_ref

型別。

5. 編譯器猛然間發現,我們定義了

auto_ptr(auto_ptr_ref rhs):ap(rhs.p){}

的建構函式,可以傳遞。

6. 順利構造

p,任務完成。

其實說白了問題很簡單,因為建構函式不能接受右值,則取「中間左值

=右值」,

然後再讓函式接受中間左值。

而這一系列過程正是利用編譯器能夠自動進行型別轉換而完成的。

關於auto ptr ref的一點問題

今天我在看the c standard library的時候,總覺的上面講的關於auto ptr ref的問題沒有說清楚,查了網上的資料發現也沒有說清。也許還有很多朋友像我一樣對此存在疑問。其實,這個問題有沒有弄清楚,對實際程式設計影像並不大,但是本著 勿在浮沙築高台 的精神,我用了乙個晚上的時間,...

關於auto ptr ref的一點問題

今天我在看the c standard library的時候,總覺的上面講的關於auto ptr ref的問題沒有說清楚,查了網上的資料發現也沒有說清。也許還有很多朋友像我一樣對此存在疑問。其實,這個問題有沒有弄清楚,對實際程式設計影像並不大,但是本著 勿在浮沙築高台 的精神,我用了乙個晚上的時間,...

關於iBatis selectKey的一點筆記

技術前提 我們使用ibatis作為持久層方案 技術場景 假設我們有兩張表,一張主表main,一張子表sub,並且主表的主鍵是由資料庫維護的自增長的主鍵,子表中有乙個字段引用這個主鍵,那麼當我們插入主表資料後,就需要馬上返回這個自增長的主鍵。解決方案 可以在insert時通過ibatis的select...