假設我有一個擁有 B 類物件的 A 類。
- A 負責創建和洗掉 B 的這個物件。
- 所有權不得轉讓給其他類別。
- 在 A 的物件被創建后,B 的物件將永遠不會被重新初始化。
通常,據我所知,在現代 C 中,我們會使用 unique_ptr 來表示 A 是此物件/參考的所有者:
// variant 1 (unique pointer)
class A {
public:
A(int param) : b(std::make_unique<B>(param)) {}
// give out a raw pointer, so that others can access and change the object
// (without transferring ownership)
B* getB() {
return b.get();
}
private:
std::unique_ptr<B> b;
};
有人建議我也可以使用這種方法:
// variant 2 (no pointer)
class A {
public:
A(int param) : b(B(param)) {}
// give out a reference, so that others can access and change the object
// (without transferring ownership)
B& getB() {
return b;
}
private:
B b;
};
據我了解,主要區別在于,在變體 2 中,記憶體是一致分配的,而在變體 1 中,B 物件的記憶體可以分配到任何地方,并且必須首先決議指標才能找到它。當然,如果 A 的公共介面的用戶可以使用 aB*或 a ,這也會有所不同B&。但在這兩種情況下,我確信所有權在我需要時保持在 A 內。
我是否總是必須使用變體 1 (unique_ptrs) 來表示所有權?使用變體 2 而非變體 1 的原因是什么?
uj5u.com熱心網友回復:
你錯過了重點unique_ptr。它的創建是為了允許通過簡單的分配進行所有權轉移。如果所有權永遠不會被轉移,那么通過使用包含來擁有一個子物件要簡單得多。
至少對于使用物件的程式員來說,記憶體分配在 C 中并不重要,因為無論物件的持續時間如何,許多物件內部都使用動態分配。一個例子是std::string。在大多數實作中,自動std::string物件仍將為其底層字符陣列使用動態記憶體。
當然,庫實作者應該關心他們的物件使用動態記憶體的方式。Small String Optimization 是在最近的標準庫實作中發明的,以避免對小字串進行動態分配(感謝 NathanOliver 的評論)。
uj5u.com熱心網友回復:
所有權可以用不同的方式表達。
您B b的變體 2 是最簡單的所有權形式。類的實體A只擁有存盤在其中的物件,b并且所有權不能轉移到另一個物件或(成員)變數。
std::unique_ptr<B> b表示對由 管理的物件的唯一但可轉讓的所有權std::unique_ptr<B>。
但是std::optional<B>, , std::vector<B>, ... or也std::variant<B,C>表示所有權。
當然,如果 A 的公共介面的用戶可以使用 B* 或 B&,這也會有所不同。但在這兩種情況下,我確信所有權在我需要時保持在 A 內。
您始終可以創建一個成員函式,B*無論該成員是B b, 或std::unique_ptr<B> b(或也為std::optional<B>, std::vector<B>, ... std::variant<B,C>)
有趣的是這段代碼:
變體 1
class A {
public:
A(int param) : b(B(param)) {}
// give out a reference, so that others can access and change the object
B& getBRef() {
return b;
}
B* getB() {
return &b;
}
private:
B b;
};
那么問題可能會少一些:
變體 2
class A {
public:
A(int param) : b(std::make_unique<B>(param)) {}
// give out a raw pointer, so that others can access and change the object
// (without transferring ownership)
B* getB() {
return b.get();
}
private:
std::unique_ptr<B> b;
};
對于變體 2 的情況,對另一個成員函式的呼叫A可能會使指標無效(如果該函式例如將另一個物件分配給unique_ptr)。而對于變體 1,回傳的指標(或參考)的有效性由實體的生命周期給出A
在任何情況下,您都必須將B *原始指標視為非擁有者,并在檔案中明確說明該原始指標的有效時間。
您選擇哪種所有權取決于實際用例。大多數時候,您會嘗試保留最簡單的所有權B b。如果該物件應該是可選的,您將使用std::optional<B>.
If the implementation requires it e.g. if you plan to use PImpl, if the data structure might prevent the use of B b (like in the case of tree- or graph-like structures), or if the owner-ship has to be transferable, you might want to use std::unique_ptr<B>.
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/339975.html
上一篇:有沒有辦法在包含在同一檔案中的不同檔案中使用相同的#define陳述句
下一篇:減少模板引數的數量
