我使用的是 Microsoft Visual Studio Community 2019, V16.5.2。我想测试列表初始化
请参阅以下测试程序:
#include <string>
void foo(std::string str) {}
int main() {
foo( {"str1", "str2"} );
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这编译没有错误和警告。为什么?
它给出了一个运行时错误: Expression: Transposed pointer range
有人可以解释一下这里发生了什么吗?
编辑。
我反汇编了代码并在调试器中运行它
foo( {"str1", "str2"} );
00F739A8 sub esp,1Ch
00F739AB mov esi,esp
00F739AD mov dword ptr [ebp-0C8h],esp
00F739B3 lea ecx,[ebp-0D1h]
00F739B9 call std::allocator<char>::allocator<char> (0F7136Bh)
00F739BE push eax
00F739BF push offset string "str2" (0F84DB8h)
00F739C4 push offset string "str1" (0F84E2Ch)
00F739C9 mov ecx,esi
00F739CB call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> ><char const *,0> (0F71569h)
00F739D0 call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> > (0F71843h)
00F739D5 add esp,1Ch
Run Code Online (Sandbox Code Playgroud)
它在第一次调用构造函数时崩溃?
Nic*_*las 16
std::string有一个模板构造函数,它从一个开始/结束迭代器对构建一个字符串。C++ 中的字符串字面量降级为const char*s。指针是迭代器。因此,列表初始化选择了开始/结束对构造函数。
您收到运行时错误,因为这两个指针实际上并未创建有效范围,而在编译时(通常)无法确定该范围。
std::string 具有以下形式的构造函数重载
template< class InputIt >
basic_string( InputIt first, InputIt last,
const Allocator& alloc = Allocator() );
Run Code Online (Sandbox Code Playgroud)
这被调用,因为"str1"并 "str2"衰减到const char*'s 并且const char*是可接受的迭代器类型。
您会崩溃,因为您传递给函数的“迭代器范围”无效。
使用带有std::string (6.)迭代器的构造函数。
template< class InputIt >
constexpr basic_string( InputIt first, InputIt last,
const Allocator& alloc = Allocator() );
Run Code Online (Sandbox Code Playgroud)
用 [ InputIt= const char*]。
然后你有 UB,因为范围{"str1", "str2"}无效。