[英]Returning Objects in C++
When returning objects from a class, when is the right time to release the memory? 从类返回对象时,什么时候该释放内存?
Example, 例,
class AnimalLister
{
public:
Animal* getNewAnimal()
{
Animal* animal1 = new Animal();
return animal1;
}
}
If i create an instance of Animal Lister and get Animal reference from it, then where am i supposed to delete it? 如果我创建了Animal Lister的实例并从中获取Animal引用,那么我应该在哪里删除它?
int main() {
AnimalLister al;
Animal *a1, *a2;
a1 = al.getNewAnimal();
a2 = al.getNewAnimal();
}
The problem here is AnimalLister doesnot have a way to track the list of Animals Created, so how do i change the logic of such code to have a way to delete the objects created. 这里的问题是AnimalLister无法跟踪创建的动物列表,因此我如何更改此类代码的逻辑以具有删除创建的对象的方法。
Depending on your usage, there are a couple of options you could go with here: 根据您的使用情况,您可以在此处选择两个选项:
Make a copy every time you create an animal: 每次创建动物时都要进行复制:
class AnimalLister { public: Animal getNewAnimal() { return Animal(); } }; int main() { AnimalLister al; Animal a1 = al.getNewAnimal(); Animal a2 = al.getNewAnimal(); }
Pros: 优点:
Cons: 缺点:
Animal
to have a well-behaved copy-constructor. Animal
具有行为良好的复制构造函数。 Animal
is larg and complex, although return value optimization can alleviate that in many situations. Animal
而复杂,则可能涉及大量复制,尽管返回值优化可以在许多情况下缓解这种情况。 Animal
as they will be sliced down to a plain Animal
, losing all the extra data in the sub-class. Animal
派生的子类,则将不起作用,因为它们将被切成普通的Animal
,从而丢失了该子类中的所有额外数据。 Return a shared_ptr<Animal>
: 返回
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(); }
Pros: 优点:
Animal
to define a copy constructor. Animal
定义副本构造函数。 Cons: 缺点:
Track all Animal
allocations in AnimalLister
在
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.
Pros: 优点:
Animal
s for a limited amount of time, and plan to release them all at once. Animal
并计划一次释放它们的情况。 Animal
s in a single delete
. delete
释放所有Animal
。 Animal
to define a copy constructor. Animal
定义副本构造函数。 Cons: 缺点:
I advise returning a std::tr1::shared_ptr
(or boost::shared_ptr
, if your C++ implementation does not have TR1) instead of a raw pointer. 我建议返回一个
std::tr1::shared_ptr
(或者,如果您的C ++实现没有TR1,则返回boost::shared_ptr
)而不是原始指针。 So, instead of using Animal*
, use std::tr1::shared_ptr<Animal>
instead. 因此,不要使用
Animal*
,而应使用std::tr1::shared_ptr<Animal>
。
Shared pointers handle reference tracking for you, and delete the object automatically if there are no references left to it. 共享指针为您处理参考跟踪,如果没有剩余的引用,则自动删除该对象。
The simpliest way is to return smart pointer instead of regular pointers. 最简单的方法是返回智能指针而不是常规指针。 For example:
例如:
std::auto_ptr< Animal> getNewAnimal()
{
std::auto_ptr< Animal > animal1( new Animal() );
return animal1;
}
If you are able to use TR1 or Boost, you can also use shared_ptr<>. 如果能够使用TR1或Boost,则也可以使用shared_ptr <>。
Kind of a classic issue with pointers and allocated memory. 与指针和分配的内存有关的经典问题。 It's about responsibility - who is responsible for cleaning up the memory allocated by the AnimalLister object.
关于责任-谁负责清理AnimalLister对象分配的内存。
You could store off a pointer to each of those allocated Animals in the AnimalLister itself and have it clean things up. 您可以在AnimalLister本身中存储一个指向每个分配的Animals的指针,并将其清理干净。
But, you do have a couple of pointers to Animals sitting there in main() that would be referencing memory that was deleted. 但是,在main()中确实有几个指向Animals的指针,它们将引用已删除的内存。
One of the reasons I think the reference counting solutions work better than rolling your own solution. 我认为引用计数解决方案比滚动自己的解决方案更好的原因之一。
implement a 'freeAnimal(Animal*)' method that makes it obvious that deletion of the animal pointer is required. 实现一个“ freeAnimal(Animal *)”方法,该方法很明显要求删除动物指针。
An alternative way is to simply return the animal object directly, no pointers, no calls to new. 另一种方法是简单地直接返回动物对象,没有指针,没有对new的调用。 The copy constructor will ensure the caller gets their own animal object that they can store on the heap or stack, or copy into a container as they desire.
复制构造函数将确保调用者获得自己的动物对象,可以将它们存储在堆或堆栈中,或者根据需要复制到容器中。
So: 所以:
class AnimalLister
{
Animal getAnimal() { Animal a; return a; }; // uses fast Return Value Optimisation
};
Animal myownanimal = AnimalLister.getAnimal(); // copy ctors into your Animal object
RVO means that returning the object instead of the pointer is actually faster (as the compiler doesn't create a new object and copies it into the caller's object, but uses the caller's object directly). RVO意味着实际上返回对象而不是指针是更快的(因为编译器不会创建新对象并将其复制到调用者的对象中,而是直接使用调用者的对象)。
在Scott Meyers的详尽讨论中 ,他得出结论,最好使用shared_ptr或auto_ptr。
Or you could follow the COM-ish approach, and apply simple reference counting. 或者,您可以遵循COM-ish方法,并应用简单的引用计数。
If the reference count hits 0, the object deletes itself. 如果引用计数达到0,则对象将自身删除。
Its ultimately what the shared_ptr does under the hood, but it gives you more control over whats going on, and in my experience easier to debug. 它最终是shared_ptr在后台执行的操作,但是它使您可以更好地控制正在发生的事情,以我的经验,它更易于调试。 (Its also very cross-platform).
(它也非常跨平台)。
I haven't given shared_ ptr too much of a chance in my development as yet, so that may serve your purposes perfectly. 到目前为止,在我的开发中,我没有给shared_ ptr太多的机会,因此这可能完全适合您的目的。
The time to release the memory occupied by an object is when you don't need that particular object any more. 释放对象占用的内存的时间就是不再需要该特定对象的时候。 In your particular case, the user of a class AnimalLister requested a pointer to a new allocated object of class Animal.
在您的特定情况下,AnimalLister类的用户请求了指向Animal类的新分配对象的指针。 So, he's the one that is responsible for freeing memory when he does need that pointer/object any more.
因此,当他确实不再需要该指针/对象时,他就是负责释放内存的人。
AnimalLister lister;
Animal* a = lister.getNewAnimal();
a->sayMeow();
delete a;
In my opinion, there's no need to over-engineer anything in this case. 我认为,在这种情况下,无需过度设计任何东西。 AnimalLister is just a factory that creates new Animal objects and that's it.
AnimalLister只是创建新Animal对象的工厂而已。
I really like Josh's answer, but I thought I might throw in another pattern because it hasn't been listed yet. 我真的很喜欢Josh的回答,但是我想我可能会抛出另一种模式,因为它尚未被列出。 The idea is just force the client code to deal with keeping track of the animals.
这个想法只是迫使客户代码处理对动物的跟踪。
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.