为什么使用cout.imbue(locale(""))会导致内存泄漏?

6

我使用的编译器是Visual VC++ 2013。下面这个最简单的程序会导致一些内存泄漏。

为什么?如何修复?

#define _CRTDBG_MAP_ALLOC

#include <stdlib.h>
#include <crtdbg.h>
#include <cstdlib>
#include <iostream>
#include <locale>

using namespace std;

int main()
{
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);

    cout.imbue(locale("")); // If this statement is commented, then OK.
}

调试窗口输出如下:
Detected memory leaks!
Dumping objects ->
{387} normal block at 0x004FF8C8, 12 bytes long.
 Data: <z h - C N   > 7A 00 68 00 2D 00 43 00 4E 00 00 00 
{379} normal block at 0x004FF678, 12 bytes long.
 Data: <z h - C N   > 7A 00 68 00 2D 00 43 00 4E 00 00 00 
{352} normal block at 0x004FE6E8, 12 bytes long.
 Data: <z h - C N   > 7A 00 68 00 2D 00 43 00 4E 00 00 00 
{344} normal block at 0x004FE498, 12 bytes long.
 Data: <z h - C N   > 7A 00 68 00 2D 00 43 00 4E 00 00 00 
{318} normal block at 0x004FD5C8, 12 bytes long.
 Data: <z h - C N   > 7A 00 68 00 2D 00 43 00 4E 00 00 00 
{308} normal block at 0x004F8860, 12 bytes long.
 Data: <z h - C N   > 7A 00 68 00 2D 00 43 00 4E 00 00 00 
Object dump complete.
Detected memory leaks!
Dumping objects ->
{387} normal block at 0x004FF8C8, 12 bytes long.
 Data: <z h - C N   > 7A 00 68 00 2D 00 43 00 4E 00 00 00 
{379} normal block at 0x004FF678, 12 bytes long.
 Data: <z h - C N   > 7A 00 68 00 2D 00 43 00 4E 00 00 00 
{352} normal block at 0x004FE6E8, 12 bytes long.
 Data: <z h - C N   > 7A 00 68 00 2D 00 43 00 4E 00 00 00 
{344} normal block at 0x004FE498, 12 bytes long.
 Data: <z h - C N   > 7A 00 68 00 2D 00 43 00 4E 00 00 00 
{318} normal block at 0x004FD5C8, 12 bytes long.
 Data: <z h - C N   > 7A 00 68 00 2D 00 43 00 4E 00 00 00 
{308} normal block at 0x004F8860, 12 bytes long.
 Data: <z h - C N   > 7A 00 68 00 2D 00 43 00 4E 00 00 00 
Object dump complete.
The program '[0x5B44] cpptest.exe' has exited with code 0 (0x0).

3
atexit()函数执行得太早了,CRT还没有清理干净。可以使用"_CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF);"代替。 - Hans Passant
1
有趣的事实是无法保证cout析构函数之前或之后它会被调用:允许在第一次使用cout之前延迟其初始化,并且使用atexit注册的函数在调用atexit时运行,在已经序列化初始化的静态持续时间对象的析构函数之前运行(C++11 §3.6.3 ¶3)。由于第一次使用coutatexit之后,因此无法确定在lambda运行时cout的析构函数是否已经被调用。C++中全局变量的规则非常疯狂。 - Matteo Italia
3
抱歉,使用“_CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF | _CRTDBG_ALLOC_MEM_DF);” - Hans Passant
1
嗯,在我的机器上运行得很好。你确定你删除了atexit() lambda吗? - Hans Passant
@HansPassant,我的真实代码是 int main() { _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF); std::cout.imbue(std::locale(""));} 问题是一样的。 - xmllmx
显示剩余5条评论
1个回答

4
我使用了 std::codecvt,遇到了类似的问题。我不确定是否是同一个原因,只是想提供一种可能找到根本原因的方法。
你可以参考 http://www.cplusplus.com/reference/locale/codecvt/in/ 中的例子。
它实际上“使用”了mylocale的成员,并且似乎没有r-value引用版本的重载。所以直接写const facet_type& myfacet = std::use_facet<facet_type>(std::locale()); 可能会导致相同的问题。
所以尝试使用:
auto myloc = locale("");
cout.imbue(myloc);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接