C++ 使用stringstream::imbue和自定义全局运算符new调试断言失败
我为这个相当本地化的问题道歉,但我希望得到其他人对它的看法,以确保我没有做明显错误的事情 <>我相信我在VisualC++运行时库中遇到了bug,或者在微软实现了代码< STD::StrugSuth中的某个地方。该问题仅在以下情况下出现:C++ 使用stringstream::imbue和自定义全局运算符new调试断言失败,c++,windows,assert,stringstream,C++,Windows,Assert,Stringstream,我为这个相当本地化的问题道歉,但我希望得到其他人对它的看法,以确保我没有做明显错误的事情 我相信我在VisualC++运行时库中遇到了bug,或者在微软实现了代码< STD::StrugSuth中的某个地方。该问题仅在以下情况下出现: 调用imbue()来更改stringstream上的区域设置,并且 使用自定义全局运算符new,该运算符返回指针相对于malloc()返回的基址的偏移量,该基址用于分配块 我已经能够通过以下最小的测试用例重现这一点: #include <sstream>
imbue()
来更改stringstream
上的区域设置,并且运算符new
,该运算符返回指针相对于malloc()
返回的基址的偏移量,该基址用于分配块#include <sstream>
static void *localMalloc(size_t bytes)
{
unsigned char *ptr = static_cast<unsigned char *>( malloc(bytes + 64) );
ptr += 64;
printf("malloc of %d bytes: %ph\n", bytes, ptr);
return ptr;
}
void *operator new(size_t bytes) { return localMalloc(bytes); }
void *operator new[](size_t bytes) { return localMalloc(bytes); }
void operator delete(void *ptr) throw() { /* do nothing */ }
void operator delete[](void *ptr) throw() { /* do nothing */ }
struct DecimalSeparator : std::numpunct<char>
{
char do_decimal_point() const
{
return '.';
}
};
int main()
{
std::stringstream ss;
ss.imbue(std::locale(std::locale(), new DecimalSeparator));
ss << 5; // <-- is_block_type_valid(header->_block_use) assertion failure here
return 0;
}
#包括
静态void*localMalloc(大小\u t字节)
{
unsigned char*ptr=static_cast(malloc(字节+64));
ptr+=64;
printf(“%d字节的malloc:%ph\n”,字节,ptr);
返回ptr;
}
void*运算符new(大小为字节){返回localMalloc(字节);}
void*运算符new[](大小为字节){return localMalloc(字节);}
void运算符delete(void*ptr)throw(){/*不执行任何操作*/}
void运算符delete[](void*ptr)throw(){/*不执行任何操作*/}
结构小数分隔符:std::numpunct
{
char do_decimal_point()常量
{
返回“.”;
}
};
int main()
{
std::stringstream-ss;
imbue(std::locale(std::locale(),新的小数分隔符));
ss这很可能不是一个bug,但是没有调用您的delete
版本,而是调用Visual Studio的调试运行库的全局delete
版本。在同一程序中有两个或多个版本的全局delete
操作符是未定义的行为
从中,发生这种情况时,行为被声明为未定义
<>从C++ ISO标准:
3.7.4动态存储持续时间[基本stc动态]
//
§2库为全局分配提供默认定义
和释放函数。一些全局分配和释放
函数是可替换的(18.61.)。<强> C++程序应提供AT
可替换分配或解除分配的最简单定义
功能。
使用Visual Studio runtime library发布版本运行Visual Studio 2015不会产生此错误,并且实际上会调用替换的全局delete
旁注:编译器保留名称\u localMalloc
:@DieterLücking很好,忘了这一点。我已删除下划线并再次测试,以确保它不是问题。请运行发布版本而不是调试版本。当运行调试版本时,您的代码的行为可能由于调试而未定义运行时调用自己版本的delete
,执行检查并查看您的指针是否无效。@PaulMcKenzie我自己也期望类似的结果,但它在发布模式下也会崩溃:未处理的异常位于…(ucrtbase.dll)在test.exe中:请求致命程序退出。
因此CRT中有东西正在调用abort()
,也许?与在线VC++编译器不一样。我也用你的代码并用VS 2015编译了一个发布版本——没有崩溃。是的,看起来就是这样。如果我改变代码生成选项以静态链接CRT而不是使用DLL,断言将不再发生。因此基本上是UB来代替全局operator delete
在任何动态链接到CRT的程序中?所有其他应用程序如何处理此问题?我猜其他应用程序都知道这一点,并且不使用调试运行库。啊,好的,所以只有调试CRT取代了operator delete
?在这种情况下,我可以使用带有调试配置的静态链接ns,但仍然使用动态链接和发布配置?我认为应该可以(除非其他人插话),因为要使用的运行库是编译设置(而不是链接器设置)在VisualC++中,如果存在错误,那么它们会显示为链接器错误。但是,如果在同一个程序中确实有两个或更多个全局代码>删除>代码>函数,则它是未定义的行为。