免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 8179 | 回复: 6
打印 上一主题 下一主题

关于函数返回指针的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-11-05 22:10 |只看该作者 |倒序浏览
有下面一段代码请各位看看这样使用指针对不对.
class AA
{
public:
        void Method() {}
};

AA* GetPointer(void)
{
        AA* pa = new AA();
        return pa;
}

int main()
{
        GetPointer()->Method(); // 这样使用会不会有问题?

        return 0;
}
个人理解: 在函数GetPointer()内, 虽然 pa 指向的是堆内存, 但 pa 本身是在栈里的. 当函数返回后这段栈空间就没有了,
那么像 GetPointer()->Method() 这样调用 AA 中的方法就有可能出现问题.
以上理解对不对, 请大家发表指点一下.

论坛徽章:
0
2 [报告]
发表于 2008-11-05 23:42 |只看该作者
虽然GetPointer(void)函数退出时pa变量已经销毁,但是函数已经把这个指针值返回给调用函数了

所以在调用函数里使用这个返回的指针值不会有问题

用完记得delete

论坛徽章:
0
3 [报告]
发表于 2008-11-06 08:37 |只看该作者
返回指针,传递了内存地址。

删除的只是一个临时量。

论坛徽章:
0
4 [报告]
发表于 2008-11-06 08:49 |只看该作者
原帖由 Pedestrian 于 2008-11-6 08:37 发表
返回指针,传递了内存地址。

删除的只是一个临时量。

:wink: :wink: :wink:

论坛徽章:
0
5 [报告]
发表于 2008-11-06 08:53 |只看该作者
好像很多人对这个问题有疑问啊,函数返回后栈上的临时变量自动销毁不是对指针指向的那块空间,而是对这个临时变量本身。指针指向的那块已经返回了。

前几天也有人问过这个问题。

论坛徽章:
0
6 [报告]
发表于 2008-11-06 21:27 |只看该作者
可能我没把问题说清楚.
我们知道在函数返回后, 栈空间的内容就要返还给系统, 也就是说系统有可能把栈用作它用, 如果刚巧把那块存有指针的空间给占了。那么在函数返回后还能找到那块堆吗?

论坛徽章:
0
7 [报告]
发表于 2008-11-06 21:30 |只看该作者
今天我想到了一个测试 GetPointer()->Method() 方法。
我现在怀疑的是在函数返回后栈空间会被系统回收,也就是说函数的返回值会被析构掉。因为这个指针是一个内置类型我们无法知道它有没有被析构。这样我就想到可以写一个类来代替那个内置的指针。以下是我写的测试代码,只列出于讨论有关的部分。
class AA
{
public:
        void Method() { cout << "AA:Method() ~~~~" << endl; }
};

class AAPtr
{
public:
        AAPtr(AA* pa);
        AAPtr(const AAPtr& Other);
        ~AAPtr();

        AA* operator -> () { return m_pa; }

private:
        AA*     m_pa;
        size_t* m_pUse;

        static const size_t LEN = 4;
        char    m_szFlag[LEN];    // 记录 AAPtr 对象是由构造函数生成还是由 copy 构造函数生成
};

AAPtr::AAPtr(AA* pa) : m_pa(pa), m_pUse(new size_t(1))
{
        strncpy_s(m_szFlag, LEN, "con", LEN);
        cout << "AAPtr's constructor: " << *m_pUse << endl;
}

AAPtr::AAPtr(const AAPtr& Other) : m_pa(Other.m_pa), m_pUse(Other.m_pUse)
{
        ++*m_pUse;
        strncpy_s(m_szFlag, LEN, "cpy", LEN);
        cout << "AAPtr's copy constructor:" << *m_pUse << endl;
}

AAPtr::~AAPtr()
{
        cout << "AAPtr's destructor: " << m_szFlag << endl;
        if (--*m_pUse == 0)
        {
                delete m_pa;
                delete m_pUse;
        }
}

AAPtr GetPointer()
{
        AAPtr ap(new AA());
        return ap;            // 在这里会调用拷贝构造函数生成一个临时对象,然后 ap 会被析构
}

int main()
{
        GetPointer()->Method();
        cout << "-------------------------" << endl;
        GetPointer();
        cout << "-------------------------" << endl;
        GetPointer(), cout << "***This is my conclusion!!!!!" << endl;
        cout << "-------------------------" << endl;

        return 0;
}

我在 AAPtr 的析构函数中插入了输出语句,这样就知道该对象有没有被析构。AAPtr 中还有一个成员变量 m_szFlag。该变量在对象被构造时会被设为 con (代表该对象是被构造生成的)。m_szFlag 在拷贝构造函数被设为 cpy (代表该对象是被拷贝生成的)。在 AAPtr 对象被析构时会输出 m_szFlag 的值。这样可以知道是哪种对象被析构了。
在看结果前先想一下结果。
如果说在 GetPointer() 返回后栈空间就没了,那么那个临时对象就会被析构掉。也就是说我们会看到两个析构函数的输出语句然后再才看到 Method() 内的输出。但结果不是这样的。以下是输出结果。

由输出顺序可以看到由构造生成的对象被析构了,但由拷贝生成的临时对象却在调用了Method() 后才被析构。
我得出一个结论,由函数返回值生成的对象并不是在函数返回后就被删除的,而是在一条语句结果后才结束的。不信再看看最后那两行输出结果。
以上是Visual Studio 8.0.50727.42输出结果。在gcc 4.3 中测试时没看到拷贝构造函数被调用,不知是否是被 gcc 优化了。但结论还是没变。
以上是我的理解,有什么问题大家说出来讨论一下。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP