什么时候需要删除由函数返回的指针

这篇博客探讨了在使用C++时,何时需要删除由函数返回的指针。关键点包括:仅凭函数声明无法确定是否需要删除,只有分配在堆上的内存需要删除,函数返回的char*或const char*并不保证可修改,返回const、static或heap上的数据是安全的,而指针转换如static_cast不一定涉及堆分配,因此不需要删除。

                                          什么时候需要删除由函数返回的指针

                                                                  created by jsjwql http://blog.youkuaiyun.com/jsjwql/

最近在做项目的时候,调用了很多第三方的API, 这些API 有很多返回char *, const char *, 有时需要delete 返回的字符串,有时不能,一删则错,晕,这有什么规则吗?

让我们先看看几个例子

// Return Pointer.cpp : Defines the entry point for the console application.

//

 

#include "stdafx.h"

#include "stdlib.h"

#include "string.h"

 

//Array

char* test1()

{

        char p[] = "test";  //静态存储区上,可以被修改,不是堆上,所以不能delete

        return p;

}

 

const char* test2()

{

        const char p[] = "test"; //const变量, 全局数据

        return p;

}

 

char* test3()

{

        static char p[] = "test"; //静态存储区上

        return p;

}

 

//pointer to const

char* test4()

{

        char *p = "test";   //p指向常量字符串,返回字符串指针不能被编辑

        return p;

}

 

const char* test5()

{

        const char *p = "test"; //指向常量的指针

        return p;

}

 

char* test6()

{

        static char p = 't'; //static, 全局数据

        return &p;

}

 

char* test7()

{

        return "test"; //常量

}

 

//pointer to heap

char* test8()

{

        char *p= new char[10]; //heap

        strcpy(p, "test");

        return p;

}

 

const char* test9()

{

        char *p= new char[10]; //heap

        strcpy(p, "test");

        return p;

}

 

char* test10()

{

        static char *p = new char[10]; //heap

        strcpy(p, "test");

        return p;

}

 

int _tmain(int argc, _TCHAR* argv[])

{

        //Array

        char *str1 = test1();

    *str1 = 'T';

        //delete str1;

 

        const char *str2 = test2();

        //*str2 = 'T';

        //delete str2;

       

        char *str3 = test3();

        *str3 = 'T';

        //delete str3;

 

        //pointer to const

        char *str4 = test4();

        //*str4 = 'T';

        //delete str4;

 

        const char *str5 = test5();

        //*str5= 'T';

        //delete str5;

 

        char *str6 = test6();

        *str6 = 'T';

        //delete str6;

 

        char *str7 = test7();

        //*str7 = 'T';

        //delete str7;

 

        //pointer to heap

         char *str8 = test8();

        *str8 = 'T';

        delete str8;

 

        const char *str9 = test9();

        //*str9 = 'T';

        delete str9;

 

        char *str10 = test10();

        *str10 = 'T';

        delete str10;

 

        return 0;

}

 

 

我列举了很多情况,但是可以总结成一下几点:

1.   仅仅从函数的声明不能判断返回的字符串是否需要delete,这是需要添加comment说明该情况。

2.   变量无非为分配在stack, heap, global等区域, 只有分配在heap上的才能被delete,不管函数返回的是char* 还是const char*

其它情况都不能删除,需要一提的是stack分配的变量在离开函数体的时候就已经不存在了。

3.   仅仅从返回的值是char* 也不能断定改函数返回的值是可以被修改的,当然一个好的函数声明在返回字符串不能被修改的情况下最好还是声明成const char*

4.   想从函数中返回有效指针,可以返回conststaticheap上的数据。我指的数据不是指指针,而是指针指向的数据类型。

test6如果改成

char* test6()

{

                char p = 't';

                static char  *q= &p;

                return  q;

}

显然不行

5.   还有常见的做static_cast, dynamic_cast等相应指针转换的时候,由于没有在heap中开辟数据,所以不需要delete

 

void test()

{

            int i = 1;

            void *p = &i;

            int *j = static_cast<int *>(p);

            delete j; //这里不能delete,由于j不在heap

     }

如果稍加修改

void test()

{

        int *i = new int('a');

        void *p = i;

        int *j = static_cast<int *>(p);

        delete j; //这里j虽然指向heap上的对象,但是也不能

//delete, static_cast并没有在heap上生成新的对象,、//delete的任务是i负责,否则重复删除

        delete i;

}

 

有一种转换情况需要注意delete,就是char* w_tchar *之间转换的时候,需要new出新的空间(当然你也可以把char*所占用的内存释放掉再在此基础上neww_tchar*来),有新的对象出现在heap上了。

6.   总之已经话,我们不是delete指针,而是delete堆上面的对象,而这个对象往往是通过指针来操作的。

 

 
在 Qt 框架中,函数返回指针是否需要手动释放,取决于该指针的来源以及 Qt 的对象所有权机制。Qt 提供了一些自动内存管理机制,尤其是在 QObject 及其派生类中,通过父子对象关系实现自动释放[^1]。 ### 1. QObject 及其派生类对象的指针返回 当一个函数返回的是 QObject 或其派生类(如 QWidget、QLabel 等)的指针时,如果该对象已经被设置为某个父对象的子对象(通过 `setParent()` 或构造函数指定父对象),则不需要手动释放该指针。当父对象被销毁时,所有子对象也会被自动销毁。 例如: ```cpp QWidget *parentWidget = new QWidget; QPushButton *button = new QPushButton("Click me", parentWidget); // parentWidget 是 button 的父对象 ``` 此时,`button` 指针不需要手动释放,当 `parentWidget` 被删除时,Qt 会自动释放 `button` 所占用的内存[^1]。 ### 2. 非 QObject 类型的指针返回 对于非 QObject 类型的对象(如 QString、QList、QMap 等),通常它们的生命周期由自身管理,返回的是值或内部指针,开发者一般不需要手动释放。例如,`QString::data()` 返回的是内部数据的指针,该指针由 QString 自身管理,不应手动 `delete`。 ### 3. 使用智能指针的情况 Qt 提供了 `QScopedPointer` 和 `std::unique_ptr` 等智能指针机制,用于自动管理堆内存。如果函数返回的是智能指针封装的原始指针,则无需手动释放内存,智能指针会在适当的时候自动释放资源。 ```cpp QScopedPointer<MyClass> createObject() { return QScopedPointer<MyClass>(new MyClass()); } // 调用后无需手动 delete ``` ### 4. 信号与槽中的指针传递 在信号与槽机制中,若通过指针传递动态分配的对象,需要注意内存管理问题。例如,在一个 `QTimer` 触发的信号中不断发送新分配的 `Data*` 指针,并在槽函数中释放,可能会导致内存泄漏,因为信号与槽的连接方式可能造成指针未被及时释放[^2]。解决方法是使用智能指针或将对象封装为值类型进行传递。 ### 5. 函数指针与回调机制 Qt 中的函数指针通常用于回调函数或信号槽连接,这些指针指向的是已存在的函数或类成员函数,不涉及堆内存分配,因此不需要释放[^3]。 ### 6. 函数返回的裸指针 如果函数返回的是裸指针(raw pointer),并且该指针指向的是通过 `new` 分配的堆内存,同时不属于 QObject 体系或未设置父子关系,则必须手动释放该指针以避免内存泄漏。例如: ```cpp MyClass* createInstance() { return new MyClass(); // 需要调用者手动释放 } ``` 调用者需在使用完毕后执行 `delete`: ```cpp MyClass* obj = createInstance(); // 使用 obj delete obj; ``` ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值