从静态变量引用非静态变量会使静态变量在静态变量

时间:2016-03-30 18:35:45

标签: c++ reference static destructor

简单地说:我想在程序退出时写入文件,所以我有一个接受文件名(char *)的对象和对Google Protobuf消息的引用(出于这些目的,你可以假装它是构造函数中的字符串&)然后将消息写入析构函数中的文件名。然后,在main()中,我初始化其中一个对象并将其声明为静态(因此当程序因任何原因退出时它将被破坏)。

我的代码在我改变某些东西(貌似)无关之前已经完美地进行了几次修改,现在它无法正常工作。现在,当对象析构时,char *和引用都指向char和Message的未初始化版本。我有以下相关代码:

using namespace std;

class WriteOnShutdown {
    private:
        const char* filename;
    public:
        MathHelper::Log& message;

        WriteOnShutdown(char* a, MathHelper::Log& b) : filename(a), message(b) {}
        ~WriteOnShutdown() {
            cout << "debug\n";
            //*filename is -52 (unitialised char)
            //READ ACCESS VIOLATION - message is still valid, but message.DebugString tries to call a pointer which hasn't been initialised yet
            cout << message.DebugString() << endl; 
        }
};

int main() {
    char filename[100];
    MathHelper::Log log;

    //Initialise filename and log

    static WriteOnShutdown write(filename, log);

    //Do program stuff here

    //Then, at the end of main(), printing write.message.DebugString() works like a charm
    cout << endl << write.message.DebugString();
    _getch();
}

2 个答案:

答案 0 :(得分:3)

您遇到问题的原因如下:

MathHelper::Log log将在您的主要返回之前被破坏,但WriteOnShutdown的析构函数将在主要返回后被称为

由于WriteOnShutdown在析构函数中使用对log的引用,因此您正在访问“悬空”。引用,调用未定义的行为,从而看到问题。

你和filename也有完全相同的问题。

明显的解决方法是将write(从某种程度上说,由于多种原因,这是一个可怕的名称)从静态变为自动变量。

答案 1 :(得分:-1)

这称为http://dygraphs.com/date-formats.html(同样适用于析构函数)。这总是一个问题,你刚才碰巧幸运。

在您的情况下,一种简单的方法是将const char* filename;更改为std::string &filename;,将MathHelper::Log& message;更改为MathHelper::Log message;。这样,在析构函数被调用时,内存仍然存在。