Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ std::string append vs push_back()

This really is a question just for my own interest I haven't been able to determine through the documentation.

I see on http://www.cplusplus.com/reference/string/string/ that append has complexity:

"Unspecified, but generally up to linear in the new string length."

while push_back() has complexity:

"Unspecified; Generally amortized constant, but up to linear in the new string length."

As a toy example, suppose I wanted to append the characters "foo" to a string. Would

myString.push_back('f'); myString.push_back('o'); myString.push_back('o'); 

and

myString.append("foo"); 

amount to exactly the same thing? Or is there any difference? You might figure that append would be more efficient because the compiler would know how much memory is required to extend the string the specified number of characters, while push_back may need to secure memory each call?

like image 810
Memento Mori Avatar asked Feb 26 '13 05:02

Memento Mori


People also ask

Does Push_back work with strings?

std::string::push_back() in C++The push_back() member function is provided to append characters. Appends character c to the end of the string, increasing its length by one. Syntax : void string:: push_back (char c) Parameters: Character which to be appended.

Does append function work with strings?

Summary. If there are few strings, then you can use any method to append them. From a readability perspective, using + operator seems better for few strings. However, if you have to append a lot of string, then you should use the list and join() function.

Can we use append in C++?

Append is a special function in the string library of C++ which is used to append string of characters to another string and returns * this operator. This is similar to push_back or += operator, but it allows multiple characters to append at the same time.


2 Answers

In C++03 (for which most of "cplusplus.com"'s documentation is written), the complexities were unspecified because library implementers were allowed to do Copy-On-Write or "rope-style" internal representations for strings. For instance, a COW implementation might require copying the entire string if a character is modified and there is sharing going on.

In C++11, COW and rope implementations are banned. You should expect constant amortized time per character added or linear amortized time in the number of characters added for appending to a string at the end. Implementers may still do relatively crazy things with strings (in comparison to, say std::vector), but most implementations are going to be limited to things like the "small string optimization".

In comparing push_back and append, push_back deprives the underlying implementation of potentially useful length information which it might use to preallocate space. On the other hand, append requires that an implementation walk over the input twice in order to find that length, so the performance gain or loss is going to depend on a number of unknowable factors such as the length of the string before you attempt the append. That said, the difference is probably extremely Extremely EXTREMELY small. Go with append for this -- it is far more readable.

like image 168
Billy ONeal Avatar answered Sep 18 '22 18:09

Billy ONeal


I had the same doubt, so I made a small test to check this (g++ 4.8.5 with C++11 profile on Linux, Intel, 64 bit under VmWare Fusion).

And the result is interesting:

 push :19 append :21 ++++ :34 

Could be possible this is because of the string length (big), but the operator + is very expensive compared with the push_back and the append.

Also it is interesting that when the operator only receives a character (not a string), it behaves very similar to the push_back.

For not to depend on pre-allocated variables, each cycle is defined in a different scope.

Note : the vCounter simply uses gettimeofday to compare the differences.

TimeCounter vCounter;  {     string vTest;      vCounter.start();     for (int vIdx=0;vIdx<1000000;vIdx++) {         vTest.push_back('a');         vTest.push_back('b');         vTest.push_back('c');     }     vCounter.stop();     cout << "push :" << vCounter.elapsed() << endl; }  {     string vTest;      vCounter.start();     for (int vIdx=0;vIdx<1000000;vIdx++) {         vTest.append("abc");     }     vCounter.stop();     cout << "append :" << vCounter.elapsed() << endl; }  {     string vTest;      vCounter.start();     for (int vIdx=0;vIdx<1000000;vIdx++) {         vTest += 'a';         vTest += 'b';         vTest += 'c';     }     vCounter.stop();     cout << "++++ :" << vCounter.elapsed() << endl; } 
like image 31
user2583872 Avatar answered Sep 16 '22 18:09

user2583872