簡體   English   中英

用C ++返回對象

[英]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無法跟蹤創建的動物列表,因此我如何更改此類代碼的邏輯以具有刪除創建的對象的方法。

根據您的使用情況,您可以在此處選擇兩個選項:

  1. 每次創建動物時都要進行復制:

     class AnimalLister { public: Animal getNewAnimal() { return Animal(); } }; int main() { AnimalLister al; Animal a1 = al.getNewAnimal(); Animal a2 = al.getNewAnimal(); } 

    優點:

    • 容易明白。
    • 不需要額外的庫或支持代碼。

    缺點:

    • 它要求Animal具有行為良好的復制構造函數。
    • 如果Animal而復雜,則可能涉及大量復制,盡管返回值優化可以在許多情況下緩解這種情況。
    • 如果您計划返回從Animal派生的子類,則將不起作用,因為它們將被切成普通的Animal ,從而丟失了該子類中的所有額外數據。
  2. 返回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定義副本構造函數。

    缺點:

    • 需要Boost或TR1庫,或其他智能指針實現。
  3. 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定義副本構造函數。
    • 無需外部庫。

    缺點:

    • 上面編寫的實現不是線程安全的
    • 需要額外的支持代碼
    • 不如前兩個方案那么清晰
    • 顯然,當AnimalLister超出范圍時,它將帶走Animals。 掛在動物上的時間不能超過掛在AnimalLister上的時間。

我建議返回一個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的指針,它們將引用已刪除的內存。

我認為引用計數解決方案比滾動自己的解決方案更好的原因之一。

  1. shared_ptr(效果很好),
  2. 返回一個簡單的指針,並告訴您的班級用戶這是他們的動物,他們有責任在完成后刪除它,
  3. 實現一個“ freeAnimal(Animal *)”方法,該方法很明顯要求刪除動物指針。

  4. 另一種方法是簡單地直接返回動物對象,沒有指針,沒有對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方法,並應用簡單的引用計數。

  • 創建對象時,請立即為其指定參考值1
  • 當任何人獲得指針的副本時,他們將AddRef()
  • 當任何人放棄其指針的副本時,他們會釋放()

如果引用計數達到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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM