2012-11-26 11 views
5

Właśnie zorientowałem się, że w Visual Studio C++ 2010, basic_string::append (iter, iter), oczywiście, nie jest implementowane przez użycie std::copy.Dlaczego basic_string :: append (iter, iter) wywołanie std :: copy?

Pierwsze pytanie:

Załóżmy teraz zaimplementować własny typ iteracyjnej, wraz ze zoptymalizowanym przeciążenia std::copy dla mojego typu iteracyjnej w celu zapewnienia bardziej efektywnego kopiowanie blokowej. Czy istnieje sposób, aby uzyskać basic_string::append, aby skorzystać z tej optymalizacji, oprócz przeciążania append również?

Czy jest jakaś szansa, że ​​basic_string::append (iter, iter) nie kopiuje znaków?

Drugie pytanie (jako punkt wyjścia dla własnej implementacji):

jest następująca gwarancją ważna?

std::string t ("JohnB"); 
std::string s; 
s.reserve (10); 
std::copy (t.begin(), t.end(), s.begin()); 
s.push_back ('\0'); 

czy powinienem lepiej użyć back_inserter? Jeśli używam numeru back_inserter - w jaki sposób mogę uniknąć kopiowania według znaków?

+0

Aby odpowiedzieć na twoje drugie pytanie: 'reserve()', po którym następuje 'copy()' jest zdecydowanie __nie ważne__. Wydrukuj 's.size()' po kopii, aby zobaczyć, dlaczego. – Blastfurnace

+0

@Blastfurnace: Ale funkcja 'resize()', a następnie 'copy()' zadziała. –

+0

Co powiesz na 'resize', po którym następuje' copy'? – JohnB

Odpowiedz

2

Definicja std::basic_string<cT, ...>::append() utrzymuje delegowania kilka czasu, zanim w końcu dochodzi do przeciążenia (21.4.6.2 [ciąg :: dopisywania] pkt 7):

basic_string& append(const charT* s, size_type n);

W tym momencie najwyraźniej nie ma już oryginalnych iteratorów. W przypadku, gdy zastanawiasz się, co dzieje się z iterator wejściowy może być przekazany do append(), GOT usuwane przez przeciążenie w pkt 17 tego samego paragrafu, który stwierdza:

Efekty: Odpowiednik append(basic_string(first, last)).

w pewnym stanie pośrednim. Jeśli biblioteka standardowa jest zaimplementowana tak, jak jest dosłownie określona przez standard, nie ma wyraźnie połączenia z std::copy().

Mimo to, tak naprawdę nie można zobaczyć swojej przeładowanej wersji std::copy(). Co może zrobić biblioteka jest moralnym odpowiednikiem

template <typename InIt> 
std::basic_string<cT, ...>& std::basic_string<cT, ...>::append(InIt begin, InIt end) { 
    if (is_forward_iterator<begin>::value) { 
     this->reserve(this->size() + std::distance(begin, end)); 
    } 
    std::copy(begin, end, back_inserter_without_capacity_check<InIt>(*this); 
} 

Teraz jest nieco inny interesujący: Nawet jeśli tak to realizowane, to nie naprawdę pomóc w odniesieniu do std::copy()! Nie możesz częściowo wyspecjalizować std::copy() (cóż, nie możesz częściowo wyspecjalizować żadnego szablonu funkcji) i typ iteratora celu nie jest zdefiniowany (w powyższej implementacji byłby to wariant sprawdzania braku zdolności std::back_inserter(), jeśli InIt jest iteratorem do przodu i w przeciwnym razie byłby on taki sam jak std::back_inserter().

+0

Hm, ale jeśli implementacja była 'using namespace std; ...; copy (begin, end, ...) ', wtedy mógłbym zdefiniować' copy' dla mojej klasy iteratora (będącego pierwszym i drugim argumentem) w przestrzeni nazw klasy iteratora, a moja wersja 'copy' zostałaby znaleziona przez ADL. Naprawdę nie sądzę, że standardowa implementacja delegowania do 'append (const char *, size_type)' jest dobrym pomysłem, ponieważ koniecznie wymaga najpierw zbudowania tablicy znaków. – JohnB

+0

Nie twierdzę, że to w ogóle Dobry Pomysł. Wszystko, co mówię, to to, co mówi standard i oznacza to, że implementacja w rzeczywistości nie nazwie wanilii, którą można znaleźć w języku ADL "copy()". Ponadto, jeśli znalazłoby ono twoje wyspecjalizowane 'copy()' na wejściowych iteratorach, mogłoby stworzyć niejednoznaczność z wersją 'copy()' wyspecjalizowaną w iteratorze wyjścia. Wydaje się bardziej uzasadnione, aby trzymać się z dala od tego i nie uważać "copy()" za punkt dostosowywania. –

5

Klasa ciągów ma własną klasę cech, która definiuje operacje, które może wykonywać na znakach, które zawiera.

Do skopiowania char s, basic_string<char> użyje std::char_traits<char>::copy (zamiast bardziej ogólnego std::copy). Prawdopodobnie mapuje się do funkcji memcpy w standardowej bibliotece C.

+0

Nie ma powodu, aby nie było przeciążenie dla 'std :: copy (const char *, const char *, char *)', aby odwzorować na 'memcpy'. –

+0

Może być bardzo dobrze, ale 'std :: string' nie może tego użyć (bezpośrednio, przynajmniej), ponieważ musi przejść przez klasę char_traits. –

+0

Właściwie, widzę tylko bezpośrednie odniesienie do 'traits :: length()', gdy szablon 'std :: basic_string' musi określić długość łańcucha wskazywanego przez' cT const * 'i' cechy :: eq() 'i' traits :: compare() 'do porównywania wartości znaków. Nie widzę żadnego wymogu, aby 'traits :: copy()' został wywołany! –

Powiązane problemy