Most definitely and absolutely carry the length around. The standard C library is infamously broken this way, which has caused no end of pain in dealing with buffer overflows. This approach is the focus of so much hatred and anguish that modern compilers will actually warn, whine and complain when using this kind standard library functions.
It is so bad, that if you ever come across this question at an interview - and your technical interviewer looks like he's got a few years of experience - pure zealotry may land the job - you can actually get pretty far ahead if you can cite the precedent of shooting someone implementing APIs looking for the C string terminator.
Leaving the emotion of it all aside, there is much that can go wrong with that NULL at the end of your string, in both reading and manipulating it - plus it is really in direct violation of modern design concepts such as defense-in-depth (not necessarily applied to security, but to API design). Examples of C APIs which carry the length abound - ex. the Windows API.
In fact, this problem was settled sometime in the '90s, today's emerging consensus is that you shouldn't even touch your strings.
Later edit: this is quite a live debate so I'll add that trusting everyone below and above you to be nice and use the library str* functions is OK, until you see classic stuff like output = malloc(strlen(input)); strcpy(output, input);
or while(*src) { *dest=transform(*src); dest++; src++; }
. I can almost hear Mozart's Lacrimosa in the background.
What is the "ninja performance gap?"
A naive approach finishing many tasks might be to start one task, wait for it to finish, and only then to start the next task. Suppose one wanted to retrieve many networked resources. The naive approach would be to send a request for the first resource, wait for the request to complete, then send the next.
If a good programmer is skilled at concurrency, such a programmer could write a program that executes many actions at a single time using all the resources of the computer on which it runs (processors, system memory, etc.). Using the network resource example above, the optimal approach would be to attempt to get many resources at the same time.
The gap between the naive approach and the most optimal approach is what these authors (and apparently others) are calling the "ninja performance gap."
Were these words chosen well?
They were likely chosen for promotional and novelty value. As the phenomenon appears to be a very real problem, I would have preferred a term that focused on the problem as opposed to the actors on one side of the gap.
Perhaps "optimized concurrency gap" would have been a better choice in words.
Why is it so large?
The naive approach to solving many problems with computers can be quite inefficient relative to known improvements.
My own experience with Project Euler demonstrated this to me, with some solutions not completing in any reasonable amount of time (minutes, hours), but other solutions to the same problem finishing blazingly fast (within a few seconds).
Bubble sort is known to be quite inefficient relative to other sorting algorithms.
Do we question the size of it?
Based on the above knowledge, I do not question the size as stated.
How can it be overcome?
The naive solution would be for the programmer to study threading and all of the relevant skills to close this gap. Closing the gap in this manner would take a lot of time and effort, both to gain the skills and to write the programs.
How do we learn to overcome it? Should we learn skillful concurrency or learn algorithms?
The paper's abstract states that using better algorithms combined with better compilers can relatively minimize the gap with much less effort required. I am inclined, without direct knowledge, to believe them.
Best Answer
If I recall, the standard allows
string::c_str()
to return pretty much anything that satisfies:NULL
string
object is calledSo in practice, this means a pointer to the internal storage; as there is no way to externally track the life of the returned pointer. I think your optimisation is safe to assume this is (small) constant time.
On a related note, if string formatting is performance limiting; you may find better luck deferring the evaluation until absolutely needed with something like Boost.Phoenix.
Boost.Format
I believe defers the formatting internally until the result is required, and you can use the same format object repeatedly without re-parsing the format string, which I've found to make a significant difference for high-frequency logging.