【发布时间】:2014-10-29 03:11:19
【问题描述】:
我遇到了一个有趣的问题,这似乎是由于 Visual Studio 2013 在调用删除运算符时实际上并未删除 fstreams 的结果。下面的代码是一个简单的程序,当在 Visual Studio 2013 中使用默认调试模式编译时,它的执行完全符合预期。当代码在发布模式下编译时(打开生成调试信息以便可以进行一些调试),删除操作符的行为取决于删除操作符的内容。如果 delete 运算符包含一个 cout,它会立即为分配的部分内存调用,如果它不包含一个 cout,它根本不会被调用,直到它运行 crtexe.c 中的退出函数,到它的时候调用 foo 互斥锁处于某种无效状态,导致“访问冲突读取位置 0xFEEEEF6”。
#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 行,则被调试的对象在遇到 crtexe.c 中的退出函数之前永远不会遇到 delete 运算符。
最大的问题是,由于某种原因,fstream(或至少不是它的全部资源)在看起来其他全局资源已被破坏后被删除,这意味着 fstream 的动态分配的内存对象正在调用自定义删除使用的资源无效后的运算符。
我应该能够为我的应用程序生成一个解决方法,此时这真的不是我关心的问题,我只是想了解正在发生的事情背后的“原因”。为什么 fstream 的析构函数和/或内存的释放会被延迟?如果有的话,可以做些什么来防止这种行为?我可以期望其他类可能会产生这种行为吗?
【问题讨论】:
-
了解事件发生的顺序会很有用。互斥锁类有可能在其构造函数/析构函数中调用 New 和 Delete 吗?这会在这里造成问题。我会在 main 的每一行之前以及您的 new 和 delete 运算符中放置一些 COUT。
-
在程序中使用 couts 时发现了一些有趣的效果。老实说,这变得很奇怪。使用新信息编辑问题。
-
这些信息至少能让我了解如何在不删除所有资源的情况下删除对象。无论 fstream 分配的 8 字节是什么,都可能以某种方式排队等待应用程序退出时被删除。我仍在试图解决为什么在删除 cout 时调试器没有命中 operator delete 的问题。操作员实际上没有运行,还是调试器没有机会看到它?
-
刚刚尝试添加“this_thread::sleep_for(chrono::seconds(5));”在退出线程之前,看看是否给定时间另一个线程会执行这 8 个字节的释放,没有这样的运气。
-
尝试将 cout 放在释放器中的锁之前。我比以前更确信您的互斥对象正在调用您的删除运算符。
标签: c++ memory-management visual-studio-2013 fstream