vb 根据pid获取句柄_C++中避免返回指向对象内部的句柄(handles)
生活随笔
收集整理的這篇文章主要介紹了
vb 根据pid获取句柄_C++中避免返回指向对象内部的句柄(handles)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
點藍色字關注“CurryCoder的程序人生”
微信公眾號:CurryCoder的程序人生
歡迎關注我,一起學習,一起進步!
1.問題的引入
假如你正在給一個應用寫一個矩形類,這個矩形由左上角和右下角的頂點坐標表示。為了表示這兩個點,我們寫一個表示點的類:class?Point{public:
????Point(int?x,?int?y);
????void?setX(int?newVal);
????void?setY(int?newVal);
????//?....
};
為了讓矩形對象的體積小一點,我們將這兩個頂點裝在另一個結構體中,并用指針指向它:struct?RectData{
????Point?ulhc;??//?左上角
????Point?lrhc;??//?右下角
};
class?Rectangle{
????//?...
private:
????std::shared_ptr?pData;??
};由于用戶想要得到點的坐標,所以需要讓矩形類要提供返回這兩個點的函數。因為矩形類是我們自定義的類,根據之前的文章C++中多用引用傳遞方式替換值傳遞方式中提到的對于自定義的類,傳遞引用方式比傳值方式更高效,所以我們讓這兩個函數返回引用:class?Rectangle{
public:
????//?...
????Point&?upperLeft()?const?{
????????return?pData->ulhc;
????}
????Point&?lowerRight()?const?{
????????return?pData->lrhc;
????}
private:
????std::shared_ptr?pData;??
};上面的代碼雖然可以通過編譯,但卻是自我矛盾的!首先,函數upperLeft()和函數lowerRight()被聲明為const成員函數。因為它們的目的是為了只返回一個對象而別的什么都不做,但兩個函數卻都返回了指向私有成員的引用,因此調用者就能通過這個引用來改變對象。Point?coord1(0,?0);
Point?coord2(100,?100);
const?Rectangle?rec(coord1,?coord2);??//?我們希望它是常對象rec
rec.upperLeft().setX(50);??//?upperLeft()的調用者rec能夠使用被返回的指向rec內部的Point成員變量的引用來更改成員
//?但是,rec實際上是不可變的,因為它是常對象
2.得到的結論從上面的代碼段中,我們可以得到下面兩個教訓:(1).數據成員的最好封裝性取決于最能破壞封裝的函數。雖然ulhc和lrhc兩個點都聲明為private,但由于存在兩個返回引用的函數的存在,它們其實相當于是public。因為public函數upperLeft()和lowerLeft()傳出了它們的引用。(2).如果一個函數返回了指向儲存在對象外部的數據成員的引用,即使這個函數聲明為了const,這個函數的調用者也能修改這個成員。原因見之前的文章盡可能使用const修飾符中的bitwise constness的局限性。除了引用,返回指針和迭代器也是相同的結果,也是由于相同的原因導致。引用、指針、迭代器都是本文標題中所說的"句柄"(handle),即接觸對象的某種方式。直接返回句柄總會帶來破壞封裝的風險,這也導致聲明為const的函數并不是真正的const。注意:"內部成員"除了內部數據還包括內部函數,即聲明為私有(private)或保護(protected)的函數。因此,對于內部函數也是一樣,也不要返回它們的句柄,否則用戶也可以通過返回的函數指針來調用它們,這樣私有的成員函數也相當于變成了公有。
3.問題的解決方法
回到上面出現自我矛盾的代碼段,如果要解決返回引用會導致數據成員被改變的問題,只需要給函數的返回類型加上一個const。如下面的代碼段所示:class?Rectangle{public:
????//?...
????//?現在返回的是const?Point&??
????const?Point&?upperLeft(){
????????return?pData->ulhc;
????}
????const?Point&?lowerRight(){
????????return?pData->lrhc;
????}
private:
????std::shared_ptr?pData;??
};這樣用戶就只能對其進行讀操作而不能進行寫操作了,給函數聲明的const也就不會騙人了。至于封裝性問題,讓用戶知道這個矩形的位置是完全合情合理的,所以我們給封裝提供了有限的放寬,讓用戶可以讀到私有數據,但堅決不能讓用戶執行寫操作。然而即使這樣,返回的句柄仍然會導致一個問題:"野句柄"(dangling handle),即這個句柄指向的對象不存在。最常見的場景是函數返回值,假如我們正在給某個GUI對象寫一個返回它邊界框的函數,返回類型是Rectangle。如下面的代碼段所示:class?GUIObject{
????//?...
};
const?Rectangle?boundingBox(const?GUIObject&?obj);
現在,客戶可能會像下面那樣使用這個函數:GUIObject*?pgo;
//?...
const?Point*?pUpperLeft?=?&(boundingBox(*pgo).upperLeft());
現在有意思的事發生了,取址運算符括號里面的函數boundingBox()會返回一個新的臨時Rectangle對象稱為temp。有了這個臨時對象之后,我們就可以獲得指向它左上角的Point對象,然后pUpperLeft自然就獲得了這個Point對象的地址。但是,temp畢竟是臨時對象。在這行代碼執行完后,temp會被銷毀,它所包含的Point對象也會被銷毀。最后,pUpperLeft存儲了一個指向不存在的對象的指針。因此,這也解釋了為什么返回指向內部成員"句柄"的函數是危險的,不管你的"句柄"是指針、引用還是迭代器;不管你的函數返回值是不是const、你的函數是不是const。但是,這不代表要杜絕這種做法,有時候不得不這樣做。例如索引[]操作符,用來獲取容器(比如std::vector)中的某個對象,它返回的是指向容器中的數據的引用,來讓你完成寫操作。記住,在我們自己設計的程序中還是盡量避免不要這么做。
4.總結
(1) 避免返回指向內部成員的"句柄"(包括指針,引用,迭代器)。不返回"句柄"能增強封裝性,讓const函數成為真正的const,也能減少"野句柄"。覺得好看,請點這里↓↓↓
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的vb 根据pid获取句柄_C++中避免返回指向对象内部的句柄(handles)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 贪吃蛇python小白_面向 pytho
- 下一篇: 【Pytorch神经网络理论篇】 31