在返回C ++对象时的复制和销毁 [英] Copying and destruction when returning a C++ object

查看:128
本文介绍了在返回C ++对象时的复制和销毁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个相当简单的测试代码:

I have a fairly simple piece of test code:

#include <stdio.h>

class PG
{
public:

PG(){
    m_ptr = new int;
    printf("Created PG %i\n", (int)m_ptr);
} 

~PG(){
    printf("Deleted PG %i\n", (int)m_ptr);
    delete (m_ptr);
}

PG& operator =(const PG& src)
{
    printf("Copied PG %i %i\n", (int)m_ptr, (int)src.m_ptr);
    return(*this);
}

private:
    int * m_ptr;
};

PG CreatePG()
{
    PG ret;
    return ret;
}

int main(int argc, char* argv[])
{
    PG test;
    test = CreatePG();
    printf("Ending\n");
    return 0;
}

如果我用GCC,VS2008或VS2012编译,我得到了我期望的结果:

创建的PG 7837600 -created测试

创建的PG 7689464 -created ret

已复制PG 7837600 768946 已恢复测试

已删除PG 7689464 -deleted ret

结束

删除了PG 7837600 - 删除的测试

If I compile this with GCC, VS2008 or VS2012 with full optimization and run it I get exactly what I expect:
Created PG 7837600 -created test
Created PG 7689464 -created ret
Copied PG 7837600 768946 -copied ret to test
Deleted PG 7689464 -deleted ret
Ending
Deleted PG 7837600 -deleted test

但是当我在VS2008或VS2012上编译时没有优化, :

已建立PG 3888456 已建立测试

建立PG 4036144 -created ret

已删除PG 4036144 -deleted ret。挂起,我们尚未复制!

已复制PG 3888456 4036144 - 我们正在尝试复制已删除的数据

已删除PG 4036144 - 这已被删除。应用程序崩溃

However when I compile on VS2008 or VS2012 with no optimization I get this:
Created PG 3888456 -created test
Created PG 4036144 -created ret
Deleted PG 4036144 -deleted ret. Hang on, we haven't copied it yet!
Copied PG 3888456 4036144 -We are now trying to copy deleted data
Deleted PG 4036144 -This has already been deleted. The application crashes

我不能相信这是一个从未修复的VS中的错误,但我也看不到我做错了。在我的应用程序中,我有一个实例,当编译一个更复杂的类为速度优化时,这种行为也发生。我知道这将是更有效的使用:

I can't believe that it is a bug in VS that has never been fixed but I also can't see what I am doing wrong. In my application I have an instance where this behaviour also occurs when compiling a more complicated class optimized for speed. I know it would be more efficient to use:

 PG test = CreatePG();

但我仍然遇到类似的问题,尽管在这种情况下显然使用copy elision:

创建的PG 11228488

删除的PG 11228488

结束

删除的PG 11228488

我仍​​然得到双删除。

but I still get a similar problem though it is obviously using copy elision in this case:
Created PG 11228488
Deleted PG 11228488
Ending
Deleted PG 11228488
I am still getting the double delete.

如果任何人都可以瞥一眼,我将非常感激。

If anyone can throw some light on this I would be very grateful.

推荐答案

这是因为您的代码违反了三项规则 :因为你没有复制构造函数,在没有看到打印输出的场景后面发生了重要的事情。

This is because your code violates the rule of three: since you do not have a copy constructor, something important happens behind the scene for which you do not see a printout.

当你没有复制构造函数时,C ++愉快地为您定义一个。这通常是你想要的确切的构造函数,除非有一种情况:当你的类明确地管理资源。在这种情况下,逐字节复制内容创建一个假别名,当相同的指针可以被删除多次。当您打开优化时,编译器跳过复制构造函数的调用(返回值优化)。然而,优化关闭后,将调用复制构造函数,然后删除 m_ptr 的副本,使实际指针指向已删除的内存。

When you do not have a copy constructor, C++ happily defines one for you. This is usually the exact constructor that you want, except in one case: when your class manages resources explicitly. In cases like that, copying content byte-for-byte creates a false alias, when the same pointer can be deleted more than once. When you turn on optimizations, the compiler skips the calls of the copy constructor (return value optimization). With optimizations off, however, the copy constructor gets called, and then the copy of the m_ptr gets deleted, leaving the actual pointer pointing to deleted memory.

这里是如何解决这个问题:

Here is how to fix this:

PG& operator =(const PG& src) {
    *m_ptr = *(other->m_ptr);
    printf("Assigned PG %x %x\n", (void*)m_ptr, (void*)src.m_ptr);
    return(*this);
}
PG(const PG& other) {
    m_ptr = new int;
    *m_ptr = *(other->m_ptr);
    printf("Copied PG %x\n", (void*)m_ptr);
}

注意:将指针转换为 int 未定义;您应该将指针转换为 void * ,并使用%x 格式说明符打印

Note: converting pointers to int is not defined; you should convert pointers to void*, and print with %x format specifier.

这篇关于在返回C ++对象时的复制和销毁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆