Nie martwiłbym się tym. Jeśli zrobisz to w pętli, łańcuchy zawsze będą wstępnie alokować pamięć, aby zminimalizować realokacje - po prostu użyj operator+=
w takim przypadku. A jeśli robisz to ręcznie, coś takiego lub dłużej
a + " : " + c
Następnie tworzy tymczasowe - nawet jeśli kompilator mógłby wyeliminować niektóre kopie zwracanej wartości. Dzieje się tak, ponieważ w wywoływanym sukcesywnie operator+
nie wie, czy parametr referencyjny odwołuje się do nazwanego obiektu, czy tymczasowo zwracany z operator+
wywołania podrzędnego . Wolałbym się tym nie przejmować, zanim nie wykonam profilowania. Ale weźmy przykład, aby to pokazać. Najpierw wprowadzamy nawiasy, aby powiązanie było jasne. Umieszczam argumenty bezpośrednio po deklaracji funkcji, która jest używana dla przejrzystości. Poniżej pokazuję, jakie jest otrzymane wyrażenie:
((a + " : ") + c)
calls string operator+(string const&, char const*)(a, " : ")
=> (tmp1 + c)
Teraz w tym dodatku tmp1
jest to , co zostało zwrócone przez pierwsze wywołanie operatora + z przedstawionymi argumentami. Zakładamy, że kompilator jest naprawdę sprytny i optymalizuje kopię zwracanej wartości. W efekcie otrzymujemy jeden nowy ciąg zawierający konkatenację a
i " : "
. Teraz dzieje się tak:
(tmp1 + c)
calls string operator+(string const&, string const&)(tmp1, c)
=> tmp2 == <end result>
Porównaj to z następującymi:
std::string f = "hello";
(f + c)
calls string operator+(string const&, string const&)(f, c)
=> tmp1 == <end result>
Używa tej samej funkcji dla tymczasowego i nazwanego ciągu! Dlatego kompilator musi skopiować argument do nowego ciągu, dołączyć do niego i zwrócić go z treści operator+
. Nie może wziąć wspomnienia czegoś tymczasowego i dołączyć do tego. Im większe wyrażenie, tym więcej kopii ciągów musi być zrobionych.
Kolejne programy Visual Studio i GCC będą obsługiwać semantykę przenoszenia języka c ++ 1x (uzupełniającą semantykę kopiowania ) i odwołania do wartości rvalue jako dodatek eksperymentalny. To pozwala ustalić, czy parametr odnosi się do tymczasowego, czy nie. To sprawi, że takie dodatki będą zadziwiająco szybkie, ponieważ wszystko powyżej skończy się w jednym „potoku dodawania” bez kopii.
Jeśli okaże się, że jest to wąskie gardło, nadal możesz to zrobić
std::string(a).append(" : ").append(c) ...
Do append
rozmowy dołączy argument *this
, a następnie powrót odniesienie do siebie. Dlatego nie jest tam kopiowanie tymczasowych. Alternatywnie operator+=
można użyć znaku, ale do ustalenia pierwszeństwa potrzebny byłby brzydki nawias.