[英]Returning Objects in C++
從類返回對象時,什么時候該釋放內存?
例,
class AnimalLister
{
public:
Animal* getNewAnimal()
{
Animal* animal1 = new Animal();
return animal1;
}
}
如果我創建了Animal Lister的實例並從中獲取Animal引用,那么我應該在哪里刪除它?
int main() {
AnimalLister al;
Animal *a1, *a2;
a1 = al.getNewAnimal();
a2 = al.getNewAnimal();
}
這里的問題是AnimalLister無法跟蹤創建的動物列表,因此我如何更改此類代碼的邏輯以具有刪除創建的對象的方法。
根據您的使用情況,您可以在此處選擇兩個選項:
每次創建動物時都要進行復制:
class AnimalLister { public: Animal getNewAnimal() { return Animal(); } }; int main() { AnimalLister al; Animal a1 = al.getNewAnimal(); Animal a2 = al.getNewAnimal(); }
優點:
缺點:
返回shared_ptr<Animal>
:
class AnimalLister { public: shared_ptr<Animal> getNewAnimal() { return new Animal(); } }; int main() { AnimalLister al; shared_ptr<Animal> a1 = al.getNewAnimal(); shared_ptr<Animal> a2 = al.getNewAnimal(); }
優點:
Animal
定義副本構造函數。 缺點:
在AnimalLister
跟蹤所有Animal
分配
class AnimalLister { vector<Animal *> Animals; public: Animal *getNewAnimal() { Animals.push_back(NULL); Animals.back() = new Animal(); return Animals.back(); } ~AnimalLister() { for(vector<Animal *>::iterator iAnimal = Animals.begin(); iAnimal != Animals.end(); ++iAnimal) delete *iAnimal; } }; int main() { AnimalLister al; Animal *a1 = al.getNewAnimal(); Animal *a2 = al.getNewAnimal(); } // All the animals get deleted when al goes out of scope.
優點:
Animal
並計划一次釋放它們的情況。 delete
釋放所有Animal
。 Animal
定義副本構造函數。 缺點:
我建議返回一個std::tr1::shared_ptr
(或者,如果您的C ++實現沒有TR1,則返回boost::shared_ptr
)而不是原始指針。 因此,不要使用Animal*
,而應使用std::tr1::shared_ptr<Animal>
。
共享指針為您處理參考跟蹤,如果沒有剩余的引用,則自動刪除該對象。
最簡單的方法是返回智能指針而不是常規指針。 例如:
std::auto_ptr< Animal> getNewAnimal()
{
std::auto_ptr< Animal > animal1( new Animal() );
return animal1;
}
如果能夠使用TR1或Boost,則也可以使用shared_ptr <>。
與指針和分配的內存有關的經典問題。 關於責任-誰負責清理AnimalLister對象分配的內存。
您可以在AnimalLister本身中存儲一個指向每個分配的Animals的指針,並將其清理干凈。
但是,在main()中確實有幾個指向Animals的指針,它們將引用已刪除的內存。
我認為引用計數解決方案比滾動自己的解決方案更好的原因之一。
實現一個“ freeAnimal(Animal *)”方法,該方法很明顯要求刪除動物指針。
另一種方法是簡單地直接返回動物對象,沒有指針,沒有對new的調用。 復制構造函數將確保調用者獲得自己的動物對象,可以將它們存儲在堆或堆棧中,或者根據需要復制到容器中。
所以:
class AnimalLister
{
Animal getAnimal() { Animal a; return a; }; // uses fast Return Value Optimisation
};
Animal myownanimal = AnimalLister.getAnimal(); // copy ctors into your Animal object
RVO意味着實際上返回對象而不是指針是更快的(因為編譯器不會創建新對象並將其復制到調用者的對象中,而是直接使用調用者的對象)。
在Scott Meyers的詳盡討論中 ,他得出結論,最好使用shared_ptr或auto_ptr。
或者,您可以遵循COM-ish方法,並應用簡單的引用計數。
如果引用計數達到0,則對象將自身刪除。
它最終是shared_ptr在后台執行的操作,但是它使您可以更好地控制正在發生的事情,以我的經驗,它更易於調試。 (它也非常跨平台)。
到目前為止,在我的開發中,我沒有給shared_ ptr太多的機會,因此這可能完全適合您的目的。
釋放對象占用的內存的時間就是不再需要該特定對象的時候。 在您的特定情況下,AnimalLister類的用戶請求了指向Animal類的新分配對象的指針。 因此,當他確實不再需要該指針/對象時,他就是負責釋放內存的人。
AnimalLister lister;
Animal* a = lister.getNewAnimal();
a->sayMeow();
delete a;
我認為,在這種情況下,無需過度設計任何東西。 AnimalLister只是創建新Animal對象的工廠而已。
我真的很喜歡Josh的回答,但是我想我可能會拋出另一種模式,因為它尚未被列出。 這個想法只是迫使客戶代碼處理對動物的跟蹤。
class Animal
{
...
private:
//only let the lister create or delete animals.
Animal() { ... }
~Animal() { ... }
friend class AnimalLister;
...
}
class AnimalLister
{
static s_count = 0;
public:
~AnimalLister() { ASSERT(s_count == 0); } //warn if all animals didn't get cleaned up
Animal* NewAnimal()
{
++count;
return new Animal();
}
void FreeAnimal(Animal* a)
{
delete a;
--s_count;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.