涉及默认复制构造函数的代码应该是段错误,但工作正常

Code involving default copy constructor should segfault, but works just fine

我做了 运行 一个小实验以更好地理解什么时候 constructors/destructors 被隐式调用,我发现了一些非常奇怪的东西。

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

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

这应该发生吗?

Is this supposed to be happening?

没有什么特别的是 "supposed" 或者更确切地说 "expected" 在这里发生 - 你正在调用未定义的行为,所以任何事情 都可能 发生,包括 "nothing".

the call to m.msg() in main() can still access it without segfaulting!

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

但这一切仅适用于这个小例子,同样,没有什么可依赖的。未定义的行为(有点不幸)并不自动意味着 "your program will segfault now"。它可能会,也可能两分钟后在完全不同的部分发生段错误,或者默默地输出错误结果,或者格式化你的硬盘。或者它可能 运行 如您所愿,这一次。