这会导致C ++中的内存泄漏吗?

时间:2021-08-18 09:00:16

I have a C++ memory management doubt, that's (obviously) related to references and pointers. Suppose I have a class Class with a method my_method:

我对C ++内存管理有疑问,这显然与引用和指针有关。假设我有一个带有方法my_method的类Class:

OtherClass& Class::my_method( ... ) {
    OtherClass* other_object = new OtherClass( ... );
    return *other_object;
}

Meanwhile in a nearby piece of code:

同时在附近的一段代码中:

{
    Class m( ... );
    OtherClass n;
    n = m.my_method( ... );
}

So, I know that there's a general rule about pointers (~ "anything new-ed, must be delete-d") to avoid memory leaks. But basicly I'm taking a reference to my heap-allocated object, so when n goes out of scope, shouldn't the destructor of OtherClass be called thus freeing the memory previously pointed by other_object? So in the end the real question is: will this lead to a memory leak?

所以,我知道有一个关于指针(〜“任何新编辑,必须删除-d”)的一般规则,以避免内存泄漏。但基本上我正在引用我的堆分配对象,所以当n超出范围时,不应该调用OtherClass的析构函数,从而释放之前由other_object指向的内存?所以最后真正的问题是:这会导致内存泄漏吗?

Thanks.

7 个解决方案

#1


It's fairly obvious that you want to return a new object to the caller that you do not need to keep any reference to. For this purpose, the simplest thing to do is to return the object by value.

很明显,您希望将新对象返回给调用者,而不需要保留任何引用。为此,最简单的方法是按值返回对象。

OtherClass Class::my_method( ... ) {
    return OtherClass( ... );
}

Then in the calling code you can construct the new object like this.

然后在调用代码中,您可以像这样构造新对象。

{
    Class m( ... );
    OtherClass n( m.mymethod( ... ) );
}

This avoids any worries about returning reference to temporaries or requiring the client to manager deletion of a returned pointer. Note, that this does require your object to be copyable, but it is a legal and commonly implemented optimization for the copy to be avoided when returning by value.

这避免了任何担心返回对临时对象的引用或要求客户端管理器删除返回的指针。请注意,这确实需要您的对象可以复制,但是按值返回时,要避免复制这是一个合法且通常实现的优化。

You would only need to consider a shared pointer or similar if you need shared ownership or for the object to have a lifetime outside the scope of the calling function. In this latter case you can leave this decision up to the client and still return by value.

如果需要共享所有权,或者对象的生命周期超出调用函数的范围,则只需要考虑共享指针或类似指针。在后一种情况下,您可以将此决定留给客户端,并仍然按值返回。

E.g.

{
    Class m( ... );

    // Trust me I know what I'm doing, I'll delete this object later...
    OtherClass* n = new OtherClass( m.mymethod( ... ) );
}

#2


Yes that will lead to a memory leak.

是的,这会导致内存泄漏。

What you'll do is, in the return statement, dereference the new object you created. The compiler will invoke the assignment operator as part of the returning and copy the CONTENTS of your new object to the object it's assigned to in the calling method.

你要做的是,在return语句中,取消引用你创建的新对象。编译器将作为返回的一部分调用赋值运算符,并将新对象的CONTENTS复制到调用方法中指定的对象。

The new object will be left on the heap, and its pointer cleared from the stack, thus creating a memory leak.

新对象将保留在堆上,并且其指针从堆栈中清除,从而产生内存泄漏。

Why not return a pointer and manage it that way?

为什么不返回指针并以这种方式管理它?

#3


Calling the destructor and freeing the memory are two distinct things in C++.

在C ++中调用析构函数并释放内存是两回事。

delete does both call the destructor and free the memory. delete[] calls the destructor for the allocated number of elements, then frees the memory.

delete会同时调用析构函数并释放内存。 delete []为分配的元素数调用析构函数,然后释放内存。

When OtherClass goes out of scope, the destructor is called, but the memory is not freed.

当OtherClass超出范围时,将调用析构函数,但不释放内存。


As a suggestion, when you feel you have thoroughly understood pointers in C++, look into smart pointers, e.g. boost smart pointers to ease your memory management life in C++. (e.g. see the article here for an introduction)

#4


You have 2 OtherClass objects:

你有2个OtherClass对象:

One is n, which is created on the stack, and successfully deleted when goes out of scope.

一个是n,它在堆栈上创建,并在超出范围时成功删除。

The other one is the one that you create on the heap, inside my_method. This one is never deleted, and it will lead to memory leak.

另一个是你在my_method中创建的那个。这个永远不会删除,它会导致内存泄漏。

#5


If possible you can consider std::auto_ptr or boost/c0x shared_ptr to ease the memory management.

如果可能,您可以考虑使用std :: auto_ptr或boost / c0x shared_ptr来简化内存管理。

#6


Usually, when a local object gets out of scope, it's memory is freed only because it's allocated on the stack and the stack gets cleaned up automatically. Since your object is allocated on the heap, there's no way it can get automatically freed. The only way to free it is to call delete explicitly.

通常,当一个本地对象超出范围时,它的内存被释放只是因为它被分配在堆栈上并且堆栈被自动清理。由于您的对象是在堆上分配的,因此无法自动释放它。释放它的唯一方法是显式调用delete。

I think you probably can do this:

我想你可能会这样做:

Declare another class DummyClass, which contain a public member that is a pointer to OtherClass object. In the constructor of DummyClass, clear the pointer to NULL. In your function, declare an object of type DummyClass, and its member pointer to create another object of type OtherClass. Then in the destructor of DummyClass, check if the pointer is NULL, if it is not, delete it. In this way your object will be cleaned up automatically when DummyClass object goes out of scope.

声明另一个类DummyClass,它包含一个公共成员,它是一个指向OtherClass对象的指针。在DummyClass的构造函数中,清除指向NULL的指针。在您的函数中,声明一个DummyClass类型的对象,并使用其成员指针创建另一个类型为OtherClass的对象。然后在DummyClass的析构函数中,检查指针是否为NULL,如果不是,则删除它。这样,当DummyClass对象超出范围时,将自动清理对象。

#7


If you insist on stack-allocation, don't use the new operator in my_method() and pass a reference to n instead, ie:

如果你坚持使用堆栈分配,不要在my_method()中使用new运算符,而是将引用传递给n,即:

void Class::my_method( OtherClass& other_object, ... ) {
    other_object.init( ... );
}

Then call my_method() like this:

然后像这样调用my_method():

{
    Class m( ... );
    OtherClass n;
    m.my_method( n, ... );
}

For this pattern to work, Class must implement some kind of init() method which allows to correctly initialize objects without calling the constructor.

要使此模式起作用,Class必须实现某种init()方法,该方法允许在不调用构造函数的情况下正确初始化对象。

#1


It's fairly obvious that you want to return a new object to the caller that you do not need to keep any reference to. For this purpose, the simplest thing to do is to return the object by value.

很明显,您希望将新对象返回给调用者,而不需要保留任何引用。为此,最简单的方法是按值返回对象。

OtherClass Class::my_method( ... ) {
    return OtherClass( ... );
}

Then in the calling code you can construct the new object like this.

然后在调用代码中,您可以像这样构造新对象。

{
    Class m( ... );
    OtherClass n( m.mymethod( ... ) );
}

This avoids any worries about returning reference to temporaries or requiring the client to manager deletion of a returned pointer. Note, that this does require your object to be copyable, but it is a legal and commonly implemented optimization for the copy to be avoided when returning by value.

这避免了任何担心返回对临时对象的引用或要求客户端管理器删除返回的指针。请注意,这确实需要您的对象可以复制,但是按值返回时,要避免复制这是一个合法且通常实现的优化。

You would only need to consider a shared pointer or similar if you need shared ownership or for the object to have a lifetime outside the scope of the calling function. In this latter case you can leave this decision up to the client and still return by value.

如果需要共享所有权,或者对象的生命周期超出调用函数的范围,则只需要考虑共享指针或类似指针。在后一种情况下,您可以将此决定留给客户端,并仍然按值返回。

E.g.

{
    Class m( ... );

    // Trust me I know what I'm doing, I'll delete this object later...
    OtherClass* n = new OtherClass( m.mymethod( ... ) );
}

#2


Yes that will lead to a memory leak.

是的,这会导致内存泄漏。

What you'll do is, in the return statement, dereference the new object you created. The compiler will invoke the assignment operator as part of the returning and copy the CONTENTS of your new object to the object it's assigned to in the calling method.

你要做的是,在return语句中,取消引用你创建的新对象。编译器将作为返回的一部分调用赋值运算符,并将新对象的CONTENTS复制到调用方法中指定的对象。

The new object will be left on the heap, and its pointer cleared from the stack, thus creating a memory leak.

新对象将保留在堆上,并且其指针从堆栈中清除,从而产生内存泄漏。

Why not return a pointer and manage it that way?

为什么不返回指针并以这种方式管理它?

#3


Calling the destructor and freeing the memory are two distinct things in C++.

在C ++中调用析构函数并释放内存是两回事。

delete does both call the destructor and free the memory. delete[] calls the destructor for the allocated number of elements, then frees the memory.

delete会同时调用析构函数并释放内存。 delete []为分配的元素数调用析构函数,然后释放内存。

When OtherClass goes out of scope, the destructor is called, but the memory is not freed.

当OtherClass超出范围时,将调用析构函数,但不释放内存。


As a suggestion, when you feel you have thoroughly understood pointers in C++, look into smart pointers, e.g. boost smart pointers to ease your memory management life in C++. (e.g. see the article here for an introduction)

#4


You have 2 OtherClass objects:

你有2个OtherClass对象:

One is n, which is created on the stack, and successfully deleted when goes out of scope.

一个是n,它在堆栈上创建,并在超出范围时成功删除。

The other one is the one that you create on the heap, inside my_method. This one is never deleted, and it will lead to memory leak.

另一个是你在my_method中创建的那个。这个永远不会删除,它会导致内存泄漏。

#5


If possible you can consider std::auto_ptr or boost/c0x shared_ptr to ease the memory management.

如果可能,您可以考虑使用std :: auto_ptr或boost / c0x shared_ptr来简化内存管理。

#6


Usually, when a local object gets out of scope, it's memory is freed only because it's allocated on the stack and the stack gets cleaned up automatically. Since your object is allocated on the heap, there's no way it can get automatically freed. The only way to free it is to call delete explicitly.

通常,当一个本地对象超出范围时,它的内存被释放只是因为它被分配在堆栈上并且堆栈被自动清理。由于您的对象是在堆上分配的,因此无法自动释放它。释放它的唯一方法是显式调用delete。

I think you probably can do this:

我想你可能会这样做:

Declare another class DummyClass, which contain a public member that is a pointer to OtherClass object. In the constructor of DummyClass, clear the pointer to NULL. In your function, declare an object of type DummyClass, and its member pointer to create another object of type OtherClass. Then in the destructor of DummyClass, check if the pointer is NULL, if it is not, delete it. In this way your object will be cleaned up automatically when DummyClass object goes out of scope.

声明另一个类DummyClass,它包含一个公共成员,它是一个指向OtherClass对象的指针。在DummyClass的构造函数中,清除指向NULL的指针。在您的函数中,声明一个DummyClass类型的对象,并使用其成员指针创建另一个类型为OtherClass的对象。然后在DummyClass的析构函数中,检查指针是否为NULL,如果不是,则删除它。这样,当DummyClass对象超出范围时,将自动清理对象。

#7


If you insist on stack-allocation, don't use the new operator in my_method() and pass a reference to n instead, ie:

如果你坚持使用堆栈分配,不要在my_method()中使用new运算符,而是将引用传递给n,即:

void Class::my_method( OtherClass& other_object, ... ) {
    other_object.init( ... );
}

Then call my_method() like this:

然后像这样调用my_method():

{
    Class m( ... );
    OtherClass n;
    m.my_method( n, ... );
}

For this pattern to work, Class must implement some kind of init() method which allows to correctly initialize objects without calling the constructor.

要使此模式起作用,Class必须实现某种init()方法,该方法允许在不调用构造函数的情况下正确初始化对象。