2016-02-04 6 views
13

Ich weiß, dass ich Array von Zeichen und auch Initialisierungsliste verwenden kann, um eine Zeichenfolge zu füllen.C++ - String - seltsames Verhalten bei der Verwendung von Initialisierungslistenkonstruktor

Es sieht so aus, dass der Compiler implizit von int zu initializer_list oder allocator hochlädt. Aber ich weiß nicht, warum es mich nicht warnt und warum es implizit ist.

Können Sie mir erklären, was passiert mit Strings s4 und 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; 
} 
+1

Können Sie mir erklären, was Sie stattdessen erwarten würden, was passiert? Ich kann nichts unbeabsichtigtes in diesem Code sehen. – dhein

+0

Ja, natürlich. Ich habe das gleiche Verhalten für beide Konstruktoren erwartet, von denen derjenige Array von Chars und Initialisiererlisten nimmt. – tomekpe

Antwort

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

Eigentlich diese Initialisierungen rufen nicht nur die std::initializer_list Konstruktor. Das zweite Argument kann nicht implizit in std::allocator konvertiert werden, sodass andere Konstruktoren berücksichtigt werden. Der Konstruktor genannt ist der mit dieser Signatur:

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

Der std::initializer_list Konstruktor wird verwendet, um ein temporäres std::string von verspannten-init-Liste zu erstellen, die als other Argument an das oben Konstruktor übergeben. Das Temporäre kann daran binden, weil es ein Verweis auf const ist. Das zweite Argument ist daher das pos Argument, das als Startpunkt für die Konstruktion einer Teilzeichenkopie verwendet wird.

s6 So sind die Zeichen in dem Intervall [3, 5) (d.h. "45") und s7 sind die Zeichen in dem Intervall [5,5) (d.h. "").

+3

Wow. Diese Fallstricke sind ein Beispiel dafür, was C++ manchmal schwer macht. – kebs

+4

Ich verstehe nicht, was sonst OP erwartet wurde ?! – dhein

+3

Sie erwarteten, dass der Compiler sich beschweren würde, dass es keine implizite Umwandlung von '5' nach 'const std :: allocator &' gab, da sie diesen Konstruktor nur als Option betrachteten. –