使用constexpr initializer_list数组在MSVC崩溃,GCC/Clang正常
MSVC编译constexpr初始化列表数组崩溃问题
问题现象
一段用于单元测试的C++代码,在GCC和Clang下可正常编译运行,但在Win10系统使用MSVC 19.38.33133编译后,无论是否启用AddressSanitizer,运行时都会崩溃。
示例代码
#include <initializer_list> #include <iostream> #include <string_view> #include <vector> using namespace std::string_view_literals; constexpr std::initializer_list<std::string_view> data[] { {}, { "aa"sv, "bb"sv, }, { "cc"sv, "dd"sv, "ee"sv, }, }; std::vector<std::string> banHashesDataGenerator(size_t index) { if (index >= std::size(data)) { throw std::invalid_argument { "index out of range" }; } std::vector<std::string> result; for (auto& item : data[index]) { result.emplace_back(std::string { item }); } return result; } int main() { for (auto& x : banHashesDataGenerator(1)) { std::cout << x << '\n'; } return 0; }
编译及运行日志
C:\Users\marek r\Downloads>cl /std:c++20 /EHcs bug.cpp /fsanitize=address /Zi Microsoft (R) C/C++ Optimizing Compiler Version 19.38.33133 for x64 Copyright (C) Microsoft Corporation. All rights reserved. bug.cpp Microsoft (R) Incremental Linker Version 14.38.33133.0 Copyright (C) Microsoft Corporation. All rights reserved. /out:bug.exe /InferAsanLibs /debug bug.obj C:\Users\marek r\Downloads>bug.exe ================================================================= ==21384==ERROR: AddressSanitizer: access-violation on unknown address 0x000000000000 (pc 0x7ff62bc718e1 bp 0x000000000000 sp 0x008189cff9a0 T0) ==21384==The signal is caused by a READ memory access. ==21384==Hint: address points to the zero page. #0 0x7ff62bc718e0 in std::basic_string<char, struct std::char_traits<char>, class std::allocator<char>>::basic_string<char, struct std::char_traits<char>, class std::allocator<char>><class std::basic_string_view<char, struct std::char_traits<char>>, 0>(class std::basic_string_view<char, struct std::char_traits<char>> const &, class std::allocator<char> const &) (C:\Users\marek r\Downloads\bug.exe+0x1400018e0) #1 0x7ff62bc7140d in banHashesDataGenerator(unsigned __int64) (C:\Users\marek r\Downloads\bug.exe+0x14000140d) #2 0x7ff62bc715a8 in main (C:\Users\marek r\Downloads\bug.exe+0x1400015a8) #3 0x7ff62bcb9bbb in invoke_main D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:78 #4 0x7ff62bcb9bbb in __scrt_common_main_seh D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288 #5 0x7ffd2b8f7343 (C:\WINDOWS\System32\KERNEL32.DLL+0x180017343) #6 0x7ffd2cba26b0 (C:\WINDOWS\SYSTEM32\ntdll.dll+0x1800526b0) AddressSanitizer can not provide additional info. SUMMARY: AddressSanitizer: access-violation (C:\Users\marek r\Downloads\bug.exe+0x1400018e0) in std::basic_string<char, struct std::char_traits<char>, class std::allocator<char>>::basic_string<char, struct std::char_traits<char>, class std::allocator<char>><class std::basic_string_view<char, struct std::char_traits<char>>, 0>(class std::basic_string_view<char, struct std::char_traits<char>> const &, class std::allocator<char> const &) ==21384==ABORTING C:\Users\marek r\Downloads>cl /std:c++20 /EHcs bug.cpp Microsoft (R) C/C++ Optimizing Compiler Version 19.38.33133 for x64 Copyright (C) Microsoft Corporation. All rights reserved. bug.cpp Microsoft (R) Incremental Linker Version 14.38.33133.0 Copyright (C) Microsoft Corporation. All rights reserved. /out:bug.exe bug.obj C:\Users\marek r\Downloads>bug.exe CRASH
问题分析与解决方案
问题本质
这段代码符合C++标准,崩溃是MSVC的已知Bug:在处理constexpr std::initializer_list<std::string_view>数组时,空初始化列表的元素会被错误地初始化,导致后续遍历访问时出现空指针引用。
保留constexpr的修复方案
以下方案可在保留constexpr测试数据的前提下解决问题:
替换容器类型:用
std::array<std::vector<std::string_view>, N>代替initializer_list数组。std::vector在C++20支持constexpr初始化,MSVC对其处理更可靠:#include <array> // ... constexpr std::array<std::vector<std::string_view>, 3> data{ std::vector<std::string_view>{}, std::vector<std::string_view>{"aa"sv, "bb"sv}, std::vector<std::string_view>{"cc"sv, "dd"sv, "ee"sv} };避免空initializer_list:如果逻辑允许,将空的初始化列表替换为包含一个空
string_view的列表,后续遍历可跳过空元素;若必须保留空列表,可显式初始化空initializer_list(部分版本MSVC可能仍存在问题,推荐方案1)。升级MSVC版本:该Bug在MSVC的后续版本中已被修复,升级编译器到较新版本可直接解决问题。
内容的提问来源于stack exchange,提问作者Marek R
相关产品推荐
相关产品推荐

