C++,这将导致内存泄漏

C++, will this cause memory leak?

本文关键字:内存 泄漏 C++      更新时间:2023-10-16

我知道我无法获得本地变量的引用,例如:

int& func1()
{
    int i;
    i = 1;
    return i;
}

我知道这是正确的,但我必须在调用func2((后删除它

int* func2()
{
    int* p;
    p = new int;

       *p = 1;
        return p;
}
int main()
{
    int *p = func2();
    cout << *p << endl;
    delete p;
    return 0;
}

如果函数是这样的:

MyClass MyFunction()
{
    return new MyClass;
}

MyClass的整个定义是:

class MyClass
{
public:
    MyClass() : num(1){}
    MyClass(MyClass*) : num(10){}
    int num;
};

这会导致内存泄漏吗?

我应该如何避免?函数返回的是一个对象而不是指针,那么我如何删除它呢

PS:代码来自《C++思考》一书第10章。原始代码为:

Picture frame(const Pictrue& pic)
{
    // Picture has a constructor Picture(*P_Node)
    // Frame_Pic derives from P_Node
    // So the constructor Picture(*P_Node) will implicitly convert Frame_Pic to Picture.
    return new Frame_Pic(pic);
}
MyClass MyFunction() 
{     
return new MyClass; 
} 

这实际上是错误的。您正在返回一个指针。所以应该是

MyClass* MyFunction()

如果你的函数是我上面提到的,如果你在使用后没有删除它,它会泄露内存。

我应该如何避免?函数返回的是一个对象而不是指针,那么我如何删除它呢

这是一个编译错误。所以删除它不会引起

如果删除从函数返回的指针,则不存在内存泄漏。然而,这很容易出错,因为这意味着函数的每个客户端都必须知道它应该删除返回值。使用智能指针(根据语义可以是shared_ptrunique_ptr(的风格要好得多。

Picture示例也是如此。如果这个对象正确地管理了它的资源(即在析构函数中删除,并且有一个好的复制构造函数和operator=(根据三规则(,那么就没有内存泄漏。

使用更新的具有指针构造函数的MyClass,我想您应该编写:

MyClass MyFunction() {
    MyClass *ptr = new MyClass;
    MyClass retval(ptr);
    delete ptr;   // the dynamically-allocated object isn't needed any more
    return retval;
}

这恰好是异常安全的,因为MyClass的构造函数不能抛出,但作为一般规则,你真的不应该在不将结果直接放入智能指针的情况下调用new

MyClass MyFunction() {
    std::unique_ptr<MyClass>(new MyClass);
    return MyClass(ptr);
}

无论如何,这是一个相当荒谬的情况——如果你要按值返回,那么根本没有理由调用new

MyClass MyFunction() {
    MyClass tmpvalue;
    return &tmpvalue; // doesn't actually return the pointer, just an object
                      // constructed from it
}

由于指针的值甚至不被指针构造函数使用,您还可以写:

MyClass MyFunction() {
    return 0; // returns an object constructed from a null pointer
}

在你引用的书中的原始代码中,我猜类Picture有一个类型为P_Node*的数据成员,它在其中存储指针值,并在其析构函数中对该指针调用delete。希望作者也能对Picture的复制构造函数和复制赋值运算符做些什么,以防止复制后出现双自由。我没有这本书,所以我不能检查我的猜测,但Picture的代码应该显示它是如何完成的。

[编辑:哦,这是Koenig和Moo的书之一。他们(非常(有能力,所以他们的Picture类可以正确地处理资源。如果没有,那是因为这是一个故意做错事的例子。]

这与您的"func2"示例相同。那些称之为"框架"的人最终需要释放返回的图片。

MyClass MyFunction()
{
    return new MyClass;
}

是不正确的,因为运算符new返回指向MyClass的指针,但函数返回的是MyClass,而不是MyClass*

一个简单的检查是:

  • 如果您在程序中使用N编号的new,则必须在程序中采用N编号的1delete以避免内存泄漏2

你在这么做吗?是的,在第一种情况下(你在做new int(,你不会这么做。没有内存泄漏。

帖子的其余部分对我来说还不够清楚!


1.通过兼容delete,我的意思是,如果你以ptr = new T[M]的形式使用new,那么兼容的delete应该是delete []ptr的形式。类似地,delete ptrptr = new T兼容

2.当然,如果你使用一些智能指针,那么你不必显式地使用delete