This test tests two fundamentally different things: a shallow copy and a deep copy. It is important to understand the difference and how to avoid deep copies in C ++, since the C ++ object by default provides the semantics of values for its instances (as is the case with the usual old data types), which means that assigning one to another usually happens for copying.
I “fixed” your test and received the following:
char* loop = 19.921 string = 0.375 slowdown = 0.0188244
Apparently, we should stop using C-style strings as they are much slower! Actually, I deliberately made my test as erroneous as yours by checking shallow copying on the side of the vs vs strcpy line on:
#include <string> #include <iostream> #include <ctime> using namespace std; #define LIMIT 100000000 char* make_string(const char* src) { return strcpy((char*)malloc(strlen(src)+1), src); } int main(int argc, char* argv[]) { clock_t start; string foo1 = "Hello there buddy"; string foo2 = "Hello there buddy, yeah you too"; start = clock(); for (int i=0; i < LIMIT; i++) foo1.swap(foo2); double stl = double(clock() - start) / CLOCKS_PER_SEC; char* goo1 = make_string("Hello there buddy"); char* goo2 = make_string("Hello there buddy, yeah you too"); char *g; start = clock(); for (int i=0; i < LIMIT; i++) { g = make_string(goo1); free(goo1); goo1 = make_string(goo2); free(goo2); goo2 = g; } double charLoop = double(clock() - start) / CLOCKS_PER_SEC; cout << "char* loop = " << charLoop << "\n"; cout << "string = " << stl << "\n"; cout << "slowdown = " << stl / charLoop << "\n"; string wait; cin >> wait; }
The main thing, and it actually comes to the bottom of your final question, you need to know what you are doing with the code. If you use a C ++ object, you should know that assigning one to another will make a copy of this object (if the assignment is not disabled, in this case you will receive an error message). You should also know when to use a link, pointer, or smart pointer to an object, and with C ++ 11, you also need to understand the difference between the semantics of movement and copying.
My real question is: why don't people use reference counting and that means we all have to be a lot more careful to avoid common std :: string performance errors?
People really use reference counting implementations. Here is an example of one of them:
shared_ptr<string> ref_counted = make_shared<string>("test"); shared_ptr<string> shallow_copy = ref_counted;
The difference is that the string does not make it internally, since it would be inefficient for those who do not need it. Things like copy-on-write usually don't work for strings for similar reasons (plus the fact that this usually makes the problem with threads). Nevertheless, we have all the building blocks right here to do copy-on-write, if we want to do this: we have the ability to swap strings without any deep copying, we can make pointers, links or smart pointers for them.
To use C ++ effectively, you must get used to this way of thinking using value semantics. If you don’t do this, you can enjoy additional security and convenience, but do it at a high cost for the efficiency of your code (unnecessary copies are certainly an important part of what makes poorly written C ++ code slower than C). After all, your original test still deals with pointers to strings, not char[] arrays. If you used arrays of characters, not pointers to them, you also need strcpy to replace them. With strings, you even have a built-in swap method to do exactly what you do in your test, so my advice is to spend a little more time learning C ++.