首页 > 解决方案 > 涉及默认复制构造函数的代码应该有段错误,但工作得很好

问题描述

我正在做一个小实验,以更好地理解构造函数/析构函数何时被隐式调用,我发现了一些非常奇怪的东西。

以下代码在调用时调用默认的复制构造函数myFunction()。在退出 myFunction() 的范围之前,我的用户定义~myClass()被调用,它应该调用free()on dangerData。但是,这似乎并没有释放dangerData

#include <cstdio>
#include <cstdlib>

class myClass {
    static int nextid;
    int myID;
    char *dangerData;

    public:

    myClass() {
        myID = nextid++;
        printf("Constructing myClass number %d\n", myID);
        dangerData = (char *)malloc(1024);
        dangerData[12] = 0;
    }

    ~myClass() {
        printf("Destructing myClass number %d. dangerData = %p\n", myID, (void *) dangerData);
        dangerData[12] = 'a'; //Mark the array
        free(dangerData); //This call chould free the array... but it doesn't!
    }

    void msg() {
        printf("Message from myClass number %d. dangerData[12] = %d\n", myID, dangerData[12]);
    }
};

int myClass::nextid = 1;

void myFunction(myClass param) {
    param.msg();
}

int main() {
    myClass m;
    myFunction(m); //Calls default copy constructor
    m.msg();
    return 0;
}

这段代码的输出是:

Constructing myClass number 1
Message from myClass number 1. dangerData[12] = 0
Destructing myClass number 1. dangerData = 02f71458. dangerData[12] = 0
Message from myClass number 1. dangerData[12] = 97
Destructing myClass number 1. dangerData = 02f71458. dangerData[12] = 97

对析构函数的第一次调用肯定是调用free()malloc 的数组,但是对m.msg()in的调用main()仍然可以在没有段错误的情况下访问它!

这应该发生吗?

标签: c++copy-constructordefault-copy-constructor

解决方案


这应该发生吗?

这里没有“假设”或者更确切地说“预期”会发生什么特别的事情——你正在调用未定义的行为,所以任何事情都可能发生,包括“什么都没有”。

main() 中对 m.msg() 的调用仍然可以在没有段错误的情况下访问它!

这并不令人非常惊讶(但同样,你不应该指望任何东西)。释放内存或多或少会告诉操作系统该内存可以自由重用/覆盖。对编译器、操作系统及其设置之间的安全性的关注越多,他们在将此内存标记为不可访问方面投入的工作就越少,而且由于您只是使用了该确切的内存位置,因此您必须在非常严格的操作系统检查下运行甚至在那里出现段错误。在两次msg()调用之间,第 13 个字符也极不可能被覆盖,因此您很可能会再次读回相同的内容。

但所有这些都只是与这个小例子有关,同样,没有什么可依赖的。未定义的行为(有点遗憾)并不自动意味着“你的程序现在会出现段错误”。它可能会,或者它可能会在两分钟后在完全不同的部分出现段错误,或者默默地输出错误的结果,或者格式化你的硬盘驱动器。或者它可能会按照您的意愿运行,这一次。


推荐阅读