A M
A M

Reputation: 15277

Copy List Initialization? Why does this compile?

I am using Microsoft Visual Studio Community 2019, V16.5.2. I want to test list initialization

Please see the following test program:

#include <string>

void foo(std::string str) {}

int main() {

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

    return 0;
}

This compiles without error and warning. Why?

It gives a runtime error: Expression: Transposed pointer range

Can somebody please explain what is happening here?


Edit.

I dissasembled the code and run it in the debugger

    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  

It crashes at the first call to the constructor?

Upvotes: 13

Views: 460

Answers (3)

NathanOliver
NathanOliver

Reputation: 180490

std::string has a constructor overload in the form of

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

and this gets called because "str1" and "str2" decay to const char*'s and const char* is an acceptable iterator type.

You get a crash because the "iterator range" you passed to the function is invalid.

Upvotes: 8

Jarod42
Jarod42

Reputation: 217135

That use the constructor with iterators of std::string (6.).

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

With [InputIt = const char*].

Then you have UB as the range {"str1", "str2"} is invalid.

Upvotes: 7

Nicol Bolas
Nicol Bolas

Reputation: 473272

std::string has a template constructor that builds a string from a begin/end iterator pair. String literals in C++ devolve down to const char*s. And pointers are iterators. Therefore, list initialization picked the begin/end pair constructor.

You got a runtime error because the two pointers do not actually create a valid range, which cannot be determined at compile-time (generally).

Upvotes: 16

Related Questions