复制列表初始化?为什么会编译?


13

我正在使用Microsoft Visual Studio Community 2019 V16.5.2。我想测试列表初始化

请参阅以下测试程序:

#include <string>

void foo(std::string str) {}

int main() {

    foo( {"str1", "str2"} );

    return 0;
}

编译时没有错误和警告。为什么?

它给出了运行时错误: 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  

它在第一次调用构造函数时崩溃了吗?


我不理解您的修改,但看起来可能是一个不同的问题,所以也许您需要为此发布新问题?
Mooing Duck

Answers:


16

std::string有一个模板构造函数,可以从一个开始/结束迭代器对构建一个字符串。C ++中的字符串文字降级为const char*s。指针是迭代器。因此,列表初始化选择了begin / end对构造函数。

您会遇到运行时错误,因为两个指针实际上并未创建有效范围,而有效范围通常无法在编译时确定。


我明白。范围构造函数。我反汇编并调试了代码。它在第一次调用构造函数时崩溃。我不明白<char const *,0>。有人可以解释一下吗?
阿明·蒙蒂尼

这意味着它正在调用template< InputIt > (InputIt first, InputIt last,...)构造函数,其中template参数iterconst char*....显然,由于某种原因,您的实现具有第二个整数参数?
Mooing Duck

@ArminMontigny:解释什么?拆卸本质上无关紧要。您的代码被声明为语法有效,但由于未传递有效范围的迭代器,因此未定义行为。您无需了解反汇编即可了解代码为何无法运行。
Nicol Bolas

8

std::string 具有以下形式的构造函数重载

template< class InputIt >
basic_string( InputIt first, InputIt last,
              const Allocator& alloc = Allocator() );

这被称为是因为"str1"并且 "str2"衰减到const char*,并且const char*是可接受的迭代器类型。

您崩溃是因为传递给该函数的“迭代器范围”无效。


谢谢,了解。+1。请查看编辑。
阿明·蒙蒂尼

7

将该构造函数与std :: string(6.)的迭代器一起使用。

template< class InputIt >
constexpr basic_string( InputIt first, InputIt last,
                        const Allocator& alloc = Allocator() );

使用[ InputIt= const char*]。

然后,您拥有UB,因为该范围{"str1", "str2"}无效。


谢谢,了解。+1。请查看编辑。
阿明·蒙蒂尼
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.