小字符串优化(调试与发布模式)
Small String Optimisation (Debug vs Release mode)
我一直在使用此示例脚本检查小字符串优化(在 MSVC 2019 中):
#include <string>
void* operator new(size_t size)
{
std::printf("global op new called, size = %zu\n", size);
void* ptr = std::malloc(size);
if (ptr)
return ptr;
else
throw std::bad_alloc{};
}
int main()
{
std::string test = "small value";
return 0;
}
请注意,我从 https://en.cppreference.com/w/cpp/memory/new/operator_new 中提取了 void* operator new(size_t size)
。
在 Release 模式下,优化按预期工作(即 new
未被调用),但在 Debug 模式下该脚本实际打印 global op new called, size = 16
。深入研究后,这似乎是由于 header xmemory
:
中的代码段所致
#if _ITERATOR_DEBUG_LEVEL == 0
#define _GET_PROXY_ALLOCATOR(_Alty, _Al) _Fake_allocator()
template <class _Alloc>
using _Container_proxy_ptr = _Fake_proxy_ptr_impl;
#else // _ITERATOR_DEBUG_LEVEL == 0
#define _GET_PROXY_ALLOCATOR(_Alty, _Al) static_cast<_Rebind_alloc_t<_Alty, _Container_proxy>>(_Al)
template <class _Alloc>
using _Container_proxy_ptr = _Container_proxy_ptr12<_Rebind_alloc_t<_Alloc, _Container_proxy>>;
#endif // _ITERATOR_DEBUG_LEVEL == 0
我们可以看到在Release模式下(即_ITERATOR_DEBUG_LEVEL == 0
)我们使用_Fake_proxy_ptr_impl
,而在Debug 模式我们使用 _Container_proxy_ptr12
它使用 new
.
我的问题很简单:为什么Debug和Release模式有这个区别?
小字符串优化在调试模式下仍然存在。
如果我们创建一个更大的 string
std::string test = "large value.large value.large value.large value.";
然后我们得到实际的string
分配
global op new called, size = 64
在调试和发布版本中。
您正在观察的是 iterator debugging 的容器代理分配(从 #if _ITERATOR_DEBUG_LEVEL
可以看出)
struct _Container_proxy { // store head of iterator chain and back pointer
您可以通过使用 /D _ITERATOR_DEBUG_LEVEL=0
构建来禁用迭代器调试(但随后它将对所有容器禁用,vector
、map
等也会被禁用)。
我一直在使用此示例脚本检查小字符串优化(在 MSVC 2019 中):
#include <string>
void* operator new(size_t size)
{
std::printf("global op new called, size = %zu\n", size);
void* ptr = std::malloc(size);
if (ptr)
return ptr;
else
throw std::bad_alloc{};
}
int main()
{
std::string test = "small value";
return 0;
}
请注意,我从 https://en.cppreference.com/w/cpp/memory/new/operator_new 中提取了 void* operator new(size_t size)
。
在 Release 模式下,优化按预期工作(即 new
未被调用),但在 Debug 模式下该脚本实际打印 global op new called, size = 16
。深入研究后,这似乎是由于 header xmemory
:
#if _ITERATOR_DEBUG_LEVEL == 0
#define _GET_PROXY_ALLOCATOR(_Alty, _Al) _Fake_allocator()
template <class _Alloc>
using _Container_proxy_ptr = _Fake_proxy_ptr_impl;
#else // _ITERATOR_DEBUG_LEVEL == 0
#define _GET_PROXY_ALLOCATOR(_Alty, _Al) static_cast<_Rebind_alloc_t<_Alty, _Container_proxy>>(_Al)
template <class _Alloc>
using _Container_proxy_ptr = _Container_proxy_ptr12<_Rebind_alloc_t<_Alloc, _Container_proxy>>;
#endif // _ITERATOR_DEBUG_LEVEL == 0
我们可以看到在Release模式下(即_ITERATOR_DEBUG_LEVEL == 0
)我们使用_Fake_proxy_ptr_impl
,而在Debug 模式我们使用 _Container_proxy_ptr12
它使用 new
.
我的问题很简单:为什么Debug和Release模式有这个区别?
小字符串优化在调试模式下仍然存在。
如果我们创建一个更大的 string
std::string test = "large value.large value.large value.large value.";
然后我们得到实际的string
分配
global op new called, size = 64
在调试和发布版本中。
您正在观察的是 iterator debugging 的容器代理分配(从 #if _ITERATOR_DEBUG_LEVEL
可以看出)
struct _Container_proxy { // store head of iterator chain and back pointer
您可以通过使用 /D _ITERATOR_DEBUG_LEVEL=0
构建来禁用迭代器调试(但随后它将对所有容器禁用,vector
、map
等也会被禁用)。