C++ std::fstream在使用预分配内存时在main之后崩溃

C++ std::fstream在使用预分配内存时在main之后崩溃,c++,memory,memory-management,C++,Memory,Memory Management,我目前在堆栈上创建了一个std::ofstream,当它分配一个全局操作符new从预先分配的缓冲区分配内存时,程序将在main完成引用std::locale0:第59行后崩溃。读取访问冲突。nodeptr被0x…作为程序崩溃点nodeptr的内存地址是实地址。我不知道为什么会发生这种情况,我只能假设这是因为我误解了分配的实际作用 此行为发生在版本在MSVC 19.10.25019 x86版上测试的构建上,构建在调试上,程序完成而不崩溃。Dr.Memory报告在调试模式下没有泄漏 最小代码: #i

我目前在堆栈上创建了一个
std::ofstream
,当它分配一个全局
操作符new
从预先分配的缓冲区分配内存时,程序将在
main
完成引用
std::locale0:第59行后崩溃。读取访问冲突。nodeptr被0x…
作为程序崩溃点
nodeptr
的内存地址是实地址。我不知道为什么会发生这种情况,我只能假设这是因为我误解了分配的实际作用

此行为发生在
版本
MSVC 19.10.25019 x86版
上测试的构建上,构建在
调试
上,程序完成而不崩溃。Dr.Memory报告在调试模式下没有泄漏

最小代码:

#include <fstream>
#include <cstdlib>

std::uint8_t *byte = static_cast<std::uint8_t*>(malloc(134217728)); // 134217728 = 128 MiB

void *operator new(size_t bytes) throw(std::bad_alloc)
    {
        return static_cast<void*>(byte); // Tested empirically, and this is only called once so this shouldnt be a cause of a problem
    }

void operator delete(void *memory) throw()
    {}

int main()
    {
        std::ofstream out("abc");

        free(byte);
    }
#包括
#包括
std::uint8_t*byte=static_cast(malloc(134217728));//134217728=128 MiB
void*运算符新(大小字节)抛出(std::bad\u alloc)
{
return static_cast(byte);//经过经验测试,只调用一次,所以这不应该是问题的原因
}
void操作符delete(void*内存)throw()
{}
int main()
{
标准:流出流(“abc”);
自由(字节);
}

有两个明显的错误:

  • 如果多次调用
    运算符new
    ,该怎么办?如果
    out
    的构造函数构造了一个子对象怎么办

  • out
    仍在范围内时,您可以释放
    字节
    。当
    out
    的析构函数运行时,您已经将其内存返回到系统

  • 试试这个:

    #include <fstream>
    #include <cstdlib>
    
    std::uint8_t *byte = static_cast<std::uint8_t*>(malloc(134217728)); // 134217728 = 128 MiB
    
    void *operator new(size_t bytes) throw(std::bad_alloc)
        {
            static int offset = 0;
            void * ret = static_cast<void*>(byte + offset);
            offset += 16 * ((bytes + 15) / 16);
            return ret;
        }
    
    void operator delete(void *memory) throw()
        {}
    
    int main()
        {
            {
                std::ofstream out("abc");
            }
    
            free(byte);
        }
    
    #包括
    #包括
    std::uint8_t*byte=static_cast(malloc(134217728));//134217728=128 MiB
    void*运算符新(大小字节)抛出(std::bad\u alloc)
    {
    静态整数偏移=0;
    void*ret=static_cast(字节+偏移量);
    偏移量+=16*((字节+15)/16);
    返回ret;
    }
    void操作符delete(void*内存)throw()
    {}
    int main()
    {
    {
    标准:流出流(“abc”);
    }
    自由(字节);
    }
    

    与以前完全相同的例外情况。对于1)这是因为我想要尽可能最小的代码,我忘了解释我测试并确保只调用一次
    new
    。(1) ,设置所有设备以使用流和其他启动程序可能涉及多个步骤allocations@M.M我的意思是永远不会给出相同的地址两次(除非分配大小为零),并对齐到16字节的边界。(这显然是我弄错了。)至少在Visual Studio 2017中,似乎没有在调试版本中调用替换的new。在发布版本中,只调用一次替换new,崩溃似乎是在清理与您的描述匹配的区域设置时发生的。代码中的注释讨论了如何销毁惰性方面。如果你在文件中看起来稍微高一点,你会发现在调试构建中,有一个新的C++类,它是一个关于自定义分配和STD::LoalALE的VisualC++错误。“CRT中的std::locale假设所有方面都在CRT堆上分配”-一个bug报告,该bug似乎与您遇到的问题不同。类似,但不确切。由于程序无论如何都会退出,因此不释放该块确实没有什么害处,因为它无论如何都会被清理,但泄漏检测器可能会抱怨。我总是想释放一切,即使我也要离开。