2014-10-29 139 views
1

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

#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... 

,然后崩溃与访问冲突。

如果您在删除操作符中设置了断点,您将看到对其的调用与输出所示完全相同。如果你离开了这些断点,但注释掉了cout行,那么调试过的命令从不碰到delete操作符,直到它到达crtexe.c中的退出函数。

最大的问题是,由于某种原因,fstream(或者至少并非全部资源)在看起来像其他全局资源已经被销毁之后被删除,这意味着fstream的动态分配的内存对象正在调用自定义它使用的资源无效后删除运算符。

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

+1

了解发生事件的顺序将是有用的。互斥类可能在其构造函数/析构函数中调用New和Delete?这会在这里造成问题。我会在每一行main和new和delete操作符前放置一些COUT。 – user3344003 2014-10-29 03:48:50

+0

发现了一些有趣的效果与couts喷洒程序。老实说,这很奇怪。用新信息编辑问题。 – Darinth 2014-10-29 04:11:35

+0

这些信息至少让我了解如何删除一个对象而不删除它的所有资源。无论是什么8字节的分配,fstream可能都会以某种方式排队,以便在应用程序退出时被删除。我仍然试图围绕为什么在删除cout时调试器不会命中删除操作符。操作员实际上是不是在运行,还是调试器没有机会看到它? – Darinth 2014-10-29 04:25:03

回答

1

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

如果该类有一个自定义operator delete()方法,全球operator delete()功能is not called可言。

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

0

如果其打印

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

问题是互斥的呼唤你的删除功能,并试图将自己锁定。

+0

不是,因为调用析构函数并不意味着调用delete操作符。只有为动态分配的对象调用delete操作符。如果互斥量使用动态分配的内存,我们会看到在输出互斥量的内存地址的初始cout之前调用新的操作符。此外,如果我为fstream以外的内存分配内存然后将其删除,问题就会消失。问题明显与fstream绑定,而不是mutex。 – Darinth 2014-10-30 21:55:43

+0

你错过了这一点。互斥体的析构函数可能会调用delete。 – user3344003 2014-10-31 01:10:53

+0

我运行了代码,但是它唯一显示的是,正如我所料,在fstream分配的8字节数据被删除之前,互斥量被删除。 如果互斥锁的析构函数调用delete,它将继续调用它,而不管是否分配了fstream。因为当fstream被移除时问题就消失了,所以这个问题不能归咎于互斥体,它会在析构体中继续调用delete。 – Darinth 2014-10-31 03:07:34

相关问题