Search code examples
c++stringc++11constructorinitializer-list

C++ string - strange behaviour when using initialization list constructor


I know that I can use array of chars and also initialization list to fill a string.

It looks that the compiler makes some implicit promotion from int to initializer_list or allocator. But I don't know why it doesn't give me any warning and why it makes it implicit.

Could you explain to me what happens with strings s4, and s5?

http://ideone.com/5Agc2T

#include <iostream>
#include <string>
using namespace std;

class A{
};

int main() {

    // string::string(charT const* s)
    string s1("12345");
    // 5 - because constructor takes into account null-terminated character
    cout << s1.size() << endl;      

    // string(std::initializer_list<charT> ilist)
    string s2({'1','2','3','4','5'});   
    // 5 - because string is built from the contents of the initializer list init.  
    cout << s2.size()<<endl;

    // string::string(charT const* s, size_type count)
    string s3("12345",3);
    // 3 -  Constructs the string with the first count characters of character string pointed to by s
    cout << s3.size() << endl;

    // basic_string( std::initializer_list<CharT> init,const Allocator& alloc = Allocator() ); - ?
    string s4({'1','2','3','4','5'},3);
    // 2 - why this compiles (with no warning) and what this result means?
    cout << s4.size() << endl;



    string s5({'1','2','3','4','5'},5);
    // 0 - why this compiles (with no warning) and what this result means?
    cout << s5.size() << endl;

    // basic_string( std::initializer_list<CharT> init,const Allocator& alloc = Allocator() );
    // doesn't compile, no known conversion for argument 2 from 'A' to 'const std::allocator<char>&'
    //string s6({'1','2','3','4','5'},A());
    //cout << s6.size() << endl;

    return 0;
}

Solution

  • string s6({'1','2','3','4','5'},3);
    string s7({'1','2','3','4','5'},5);
    

    Actually, those initializations don't just call the std::initializer_list constructor. The second argument cannot be implicitly converted to std::allocator, so other constructors are considered. The constructor called is the one with this signature:

    basic_string( const basic_string& other, 
                  size_type pos, 
                  size_type count = std::basic_string::npos,
                  const Allocator& alloc = Allocator() );
    

    The std::initializer_list constructor is used to create a temporary std::string from the braced-init-list to pass as the other argument to the above constructor. The temporary can bind to that because it's a reference-to-const. The second argument, therefore, is the pos argument, which is used as the starting point of a substring copy construction.

    So s6 is the characters in the interval [3, 5) (i.e. "45") and s7 is the characters in the interval [5,5) (i.e. "").