繁体   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