[英]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.