您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“C++為什么原始指針不應(yīng)擁有所有權(quán)”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“C++為什么原始指針不應(yīng)擁有所有權(quán)”吧!
R.3: 原始指針(T*)不應(yīng)擁有所有權(quán)
這一點(diǎn)不存在任何例外(無(wú)論是C++標(biāo)準(zhǔn)還是大部分代碼)而且大多數(shù)原始指針就是沒(méi)有所有權(quán)的。我們需要所有權(quán)指針被定義出來(lái),這樣就可以可靠地,高效地刪除所有權(quán)指針指向的對(duì)象。
Example(示例)
void f()
{
int* p1 = new int{7}; // bad: raw owning pointer
auto p2 = make_unique<int>(7); // OK: the int is owned by a unique pointer
// ...
}
unique_ptr通過(guò)(即使在發(fā)生異常的情況下)保證對(duì)象的刪除來(lái)防止內(nèi)存泄露。而T*不會(huì)。
Example(示例)
template<typename T>
class X {
public:
T* p; // bad: it is unclear whether p is owning or not
T* q; // bad: it is unclear whether q is owning or not
// ...
};
我們可以通過(guò)明確地賦予所有權(quán)來(lái)解決這個(gè)問(wèn)題。
template<typename T>
class X2 {
public:
owner<T*> p; // OK: p is owning
T* q; // OK: q is not owning
// ...
};
例外主要來(lái)源于既有代碼,特別是那些由于A(yíng)BIs必須保持C兼容性或者包含C或C風(fēng)格C++接口的情況。事實(shí)上存在成百萬(wàn)行的代碼違反這條反對(duì)T*持有所有權(quán)的準(zhǔn)則,它們不能被忽略。我們很高興地看到軟件工具可以將20年以上的老代碼轉(zhuǎn)換為嶄新的現(xiàn)代C++代碼,我們鼓勵(lì)這類(lèi)工具的開(kāi)發(fā)、部署和使用,我們甚至向這個(gè)領(lǐng)域的研究做出了貢獻(xiàn),而且將繼續(xù)做出貢獻(xiàn)。然而這需要時(shí)間:“既有代碼”的產(chǎn)生快于我們翻新舊代碼的速度,因此這個(gè)過(guò)程將會(huì)持續(xù)一些年。
不可能所有的代碼都被重寫(xiě)(即使存在優(yōu)秀的轉(zhuǎn)換軟件),很快重寫(xiě)更不可能。這個(gè)問(wèn)題不可能通過(guò)將所有具有所有權(quán)指針轉(zhuǎn)換為unique_ptr和shared_ptr來(lái)解決,一部分的原因是基礎(chǔ)的資源持有者需要/使用具有所有權(quán)的原始指針(同時(shí)也是簡(jiǎn)單指針)。例如,普通的vector實(shí)現(xiàn)包含一個(gè)所有權(quán)指針和兩個(gè)非所有權(quán)指針。很多ABI(本質(zhì)上講所有面向C語(yǔ)言的接口)使用T*,其中有些具有所有權(quán)。因?yàn)樾枰S持C語(yǔ)言可編譯,因此有些接口不能簡(jiǎn)單地加注所有權(quán)(雖然這是很少見(jiàn)的宏的好用法,它只是在C++模式時(shí)展開(kāi)成為所有權(quán)指針)。
Note(注意)
owner<T*>沒(méi)有包含任何超過(guò)T*的語(yǔ)義。它不修改任何代碼就可以使用而且不會(huì)影響ABI。它只是面向程序員和分析工具的一個(gè)指示信息。例如,如果owner<T*>是某類(lèi)的成員,那個(gè)最好準(zhǔn)備一個(gè)析構(gòu)函數(shù)來(lái)銷(xiāo)毀它。
Example, bad(反面示例)
返回一個(gè)(原始)指針會(huì)增加調(diào)用者生命周期管理的不確定性;即:誰(shuí)應(yīng)該銷(xiāo)毀指針指向的對(duì)象?
Gadget* make_gadget(int n)
{
auto p = new Gadget{n};
// ...
return p;
}
void caller(int n)
{
auto p = make_gadget(n); // remember to delete p
// ...
delete p;
}
這段代碼可以排除來(lái)自?xún)?nèi)存泄漏問(wèn)題的痛苦,但是增加了虛假的分配和釋放操作和沒(méi)有必要的冗長(zhǎng)性。如果Gadget很容易移出函數(shù)(也就是說(shuō),很小或者存在高效的移動(dòng)操作),直接只用傳值(參照“輸出“返回值)。
Gadget make_gadget(int n)
{
Gadget g{n};
// ...
return g;
}
這條準(zhǔn)則適用于工廠(chǎng)函數(shù)。
Note(注意)
如果需要指針語(yǔ)義(例如因?yàn)榉祷氐闹羔樞枰赶蝾?lèi)層次中的基類(lèi)(某個(gè)接口)),返回一個(gè)智能指針。
Enforcement(實(shí)施建議)
(Simple) Warn on delete of a raw pointer that is not an owner<T>.
(簡(jiǎn)單)警告銷(xiāo)毀owner<T>類(lèi)型之外的原始指針的情況。
(Moderate) Warn on failure to either reset or explicitly delete an owner<T> pointer on every code path.
(中等)如果沒(méi)有在所有代碼路徑上重置或者銷(xiāo)毀onwer<T>指針,發(fā)出警告。
(Simple) Warn if the return value of new is assigned to a raw pointer.
(簡(jiǎn)單)如果new的返回值賦給原始指針,發(fā)出警告。
(Simple) Warn if a function returns an object that was allocated within the function but has a move constructor. Suggest considering returning it by value instead.、
(簡(jiǎn)單)如果一個(gè)函數(shù)返回的對(duì)象在函數(shù)內(nèi)分配內(nèi)存,但是包含移動(dòng)構(gòu)造函數(shù)。提出建議通過(guò)傳值方式返回。
到此,相信大家對(duì)“C++為什么原始指針不應(yīng)擁有所有權(quán)”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢(xún),關(guān)注我們,繼續(xù)學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。