在发布模式下调用delete时未删除fstream

时间:2014-10-29 03:11:19

标签: c++ memory-management visual-studio-2013 fstream

我遇到了一个有趣的问题,似乎是visual studio 2013在调用delete运算符时实际上没有删除fstream的结果。下面的代码是一个简单的程序,当使用默认调试模式在visual studio 2013中编译时,执行完全符合预期。当代码在发布模式下编译时(启用生成调试信息以便可以进行某些调试),删除操作符行为似乎取决于删除操作符的内容。如果删除操作符包含一个cout,则会立即调用分配的内存部分,如果它不包含cout,则直到它在crtexe.c中运行exit函数时才会被调用,并且当它被运行时调用foo互斥锁处于某种无效状态,导致“访问冲突读取位置0xFEEEFEF6”。

#include <cstdlib>

#include <fstream>
#include <mutex>
#include <iostream>
using namespace std;

mutex foo;

void* operator new(unsigned int size)
{
    lock_guard<mutex> memoryLock(foo);
    void* alloc = malloc(size);
    cout << "Allocating " << size << " bytes for " << alloc << endl;
    return alloc;
}

void* operator new[](unsigned int size)
{
    lock_guard<mutex> memoryLock(foo);
    void* alloc = malloc(size);
    cout << "Allocating " << size << " bytes for " << alloc << endl;
    return alloc;
}

void operator delete(void* ptr)
{
    lock_guard<mutex> memoryLock(foo);
    cout << "Deallocating " << ptr << endl;
    free(ptr);
}

void operator delete[](void* ptr)
{
    lock_guard<mutex> memoryLock(foo);
    cout << "Deallocating " << ptr << endl;
    free(ptr);
}

int main()
{
    cout << "Address of Mutex: " << &foo << endl;
    cout << "Creating fstream... " << endl;
    fstream *blarg = new fstream("blarg.txt", ios::out);
    cout << "Deleteing fstream..." << endl;
    delete blarg;
    cout << "fstream deleted..." << endl;

    cout << "Exiting main..." << endl;
    return 0;
}

该程序输出:

Address of Mutex: 00DD6658
Creating fstream...
Allocating 192 bytes for 003ABB00
Allocating 8 bytes for 00392A40
Deleteing fstream...
Deallocating 003ABB00
fstream deleted...
Exiting main...

然后因访问冲突而崩溃。

如果在delete运算符内设置断点,您将看到对它的调用与输出指示完全相同。如果你保留这些断点,但注释掉cout行,那么调试后永远不会命中delete操作符,直到它到达crtexe.c中的exit函数。

最大的问题是,由于某些原因,fstream(或至少不是所有的资源)在看起来像其他全局资源被破坏之后被删除,这意味着fstream的动态分配的内存对象正在调用自定义删除运算符使用后的资源无效。

我应该能够为我的应用程序制作一个解决方法,这在我看来并不是我关心的问题,我只是想了解正在发生的'为什么'。为什么fstream的析构函数和/或释放它的内存会被延迟?如果有的话,可以采取什么措施来防止这种行为?我可以期待其他类可能产生这种行为吗?

2 个答案:

答案 0 :(得分:1)

  

我可以期待其他类可能产生这种行为吗?

如果班级有自定义operator delete()方法,则全局operator delete()函数is not called

在这种情况下,fstream可能有这样的方法,并且只有在OS运行时准备好释放对象时才会调用全局函数。 Visual C ++也可以做一些完全不同的事情。

答案 1 :(得分:0)

如果打印

class MyMutex : public mutex
{
public:
    virtual ~MuMutex () { cout << "Deleting Mutex" << endl ; }
} mutex ;

问题是互斥锁正在调用你的删除功能并尝试锁定自己。