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

时间:2018-05-14 13:45:09

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

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

以下代码在调用myFunction()时调用默认的复制构造函数。在退出myFunction()的范围之前,我的用户定义的~myClass()被调用,应该在free()上调用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

对析构函数的第一次调用是肯定在malloc&lt; d}数组上调用free(),但m.msg()中对main()的调用仍然可以在没有segfaulting的情况下访问它!

这应该发生吗?

1 个答案:

答案 0 :(得分:2)

  

这应该发生吗?

没有什么特别的“假设”或“预期”在这里发生 - 你正在调用未定义的行为,所以任何都可以发生,包括“没有”。

  

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

这并不令人惊讶(但同样,你不应该依赖它)。释放内存或多或少告诉操作系统可以自由地重用/覆盖该内存。对编译器,操作系统及其设置之间的安全性的关注越多,他们将这个内存标记为无法访问的工作就越少,并且由于您只是使用了那个确切的内存位置,因此您必须在非常严格的操作系统检查下运行甚至在那里得到一个段落错误。在两个xmlns:sys="clr-namespace:System;assembly=mscorlib" 调用之间的时间内,第13个字符被覆盖的可能性极小,因此您可能会再次回读相同的内容。

但这一切只与这个小例子有关,而且再一次,没有什么可以依赖的。未定义的行为(有点不幸)并不自动意味着“您的程序现在会出现段错误”。它可能会,或者它可能在两分钟后在一个完全不同的部分发生段错误,或者默默地输出错误的结果,或者格式化你的硬盘。或者它可以按照您的意图运行,这一次。