tags:

views:

541

answers:

7

I need to pass const char * to a function. Before I pass it, I usually need to build it from some variables. I can never decide which approach is more elegant, and overall better:

  • Allocate an array long enough to fit the text and use sprintf to build the final variable and pass it to the function.
  • Initialize string s with a variable using the + operator (concatenation) and then pass it to the function using s.c_str().

Cons of using an array: May not fit the entire text.
Pro: Fast.

Cons of using a string: I don't need to worry about memory management, easy to build. Pro: Slow.

My second question is: How do you usually build a complete string from other variable strings?

+5  A: 

One crash from a too-short buffer will negate all the speed savings you get from sprintf. I'm not convinced it's faster anyway. And even if it is, is the difference significant enough to worry about?

Mark Ransom
+1. The only real good reason to use char arrays instead is if you are working on a RealTime system and need deterministic behavior from that code.
T.E.D.
+14  A: 

Unless it's absolutely performance critical, I tend to use a std::stringstream to build up the string from its components and then c_str() the resulting string. This is safe as there isn't really a chance of a buffer overflow this way and usually fast enough.

If the profiler tells me that building up the string is a hot spot then you will have to trade some safety for speed and start using something like sprintf but I'd rather avoid this. Overall I'd use this as a last resort.

Timo Geusch
You do not have to trade in the safety since you can use snprintf instead of sprintf.
Mikael Auno
snprintf is still pretty unsafe, even if there's not a problem with buffer overflow. Stick with stringstream, or at the very least, string. If, after profiling the code, you find out that this is a bottleneck, you can optimize later.
mos
snprintf is not safe. It protects against buffer overflows, sure, but it does nothing to ensure type safety.
jalf
snprintf should be avoided because you can easily run into off-by-one errors (which can be exploitable in certain situations). use snprintf_s instead
jn_
+1  A: 

I almost always use string and stringstream, due to the easier memory management. sprintf and other old-fashioned-C library calls are just too error-prone.

The one benefit of sprintf-style functions over stringstream is that it makes it easy to use different format strings at runtime, for internationalization purposes. But you should definitely use snprintf or one of the other "safer" variants of it.

Kristopher Johnson
Boost formatting will do the internationalizastion bit you require.
Martin York
+11  A: 

This really sounds like a case for Herb Sutter's excellent article The String Formatters of Manor Farm.

For the record: I myself use std::ostringstream, build the string up and pass oss.str().c_str().

Johannes Schaub - litb
+1  A: 

When it comes to C++ and elegance, I tend to follow two rules:

  1. Say what you mean.
  2. Profile first, optimize later.

You're talking about concatenating strings here, so this is the code that comes to mind:

std::string s = s1 + s2 + s3 + s4;
foo(s.c_str());

To "say what you mean," I reach for operator +. Using std::stringstream (a stream of strings) is pretty good too, but I don't immediately go for another #include just to concatenate strings. It's a matter of personal preference I guess. I definitely don't think of building up a raw char array by hand.

In terms of performance, my guess is that operator + is probably the slowest method of putting the strings together. But even a slow method might be fast enough for your purposes.

Kristo
A: 

Repeat the following to yourself three times every morning when you wake up and three times every night before you go to bed:

"Premature optimization is the root of all evil." - Knuth

In other words, go with the safe, idiomatic C++ way. Speed should be fixed when (and if) it becomes an issue, not before, ESPECIALLY if fixing it before makes your code more error-prone.

As for your second question: look up ropes.

Imagist
First of all, your quote is incorrect - check what exactly Knuth said (about percentage).Secondly, perhaps it sounds like a heresy, but this Knuth's saying is nothing more then a dogma, especially in the way you recommend to use it. I think this dogma did more harm than good - programmers learned not to care about performance of their code. If you suspect particular place will be a hot spot, optimise it right away, during design phase. This approach never failed on me.Last one - ropes are useless for people who need good old null-terminated strings.
qrdl
@qrdl... I guess you're right.http://shreevatsa.wordpress.com/2008/05/16/premature-optimization-is-the-root-of-all-evil/
kenny
You know, I've heard way too may "Script Kitties," who NEVER even consitered reading Knuth quote that. Typically they use it justify why they are using a scripting language, and not even to justify thier design and as an excuse not to the thing which I was always told you should do first before you write any code... THINK. Moores law can't overcome inefficiently designed software written on scripting languages, implemented on a language VM, running on a virtual Linux server being timeshared by 100 clients.
NoMoreZealots
@Pete Exactly my point!
qrdl
@qrdl I'll look up the Knuth quote.It's not that you shouldn't care about the performance of your code. It's just that there are other concerns; type-safety, memory management, etc.; which should be prioritized in this and many other cases. The logic is simple: don't fix things that MIGHT be broken when there are other things that ARE broken staring you in the face.As for ropes vs. strings, strings are useless for people who need good old ropes. What's your point? Each has its uses. I suggested ropes because ropes excel when there's concatenation, which is what he asked about.
Imagist
@Pete Eddy Not only have I read Knuth's Art of Computer Programming Vols. 1-3, but I write a significant amount of C/C++ in my personal projects. Please don't justify your position by attacks on those who disagree with you.It's not about relying on Moore's law, it's about K.I.S.S. Of course you shouldn't make any glaring design errors (don't sort a billion entries with bubblesort!). But also don't overcomplicate your code and sacrifice type-safety to fix phantom performance problems.
Imagist
@qrdl There is a world of difference between the "small efficiencies" and the world we live in today. There are two major catagories of programmer, those who view programming as a means to an end, and those who actually do it for the intellectual challenge. People who don't care about efficiency don't REALLY like to program that much.
NoMoreZealots
The advancement of technology never occurs by accepting the prior solution to a problem. That's reason C++ exist at all. Don't tell someone they should take the easy answer all the time. Asking a general question elegancy vs efficiency shouldn't be boldly rejected everytime it's asked. (Which I've found to the case by in large, most people wave their hands quote Knuth and tell you screw efficiency.)
NoMoreZealots
@PeteEddy Bullshit. I don't just like programming, I love it. I simply don't feel the need to fix non-problems when there are real, interesting problems to be solved. Instead of accusing people who disagree with you of not REALLY loving programming, why don't you provide an actual justification for your opinion?
Imagist
@PeteEddy2 Sometimes the easy answer is the right answer. In other cases there are problems that don't need to be solved. Question like this can't be answered, because we don't know whether it will cause a problem. With modern compilers there is a reasonable chance that the entire question is irrelevant because they both get optimized to the same thing. Human error due to brittle code, on the other hand, is ALWAYS a problem. Optimizing when there's no known performance problem and there IS a brittle code problem is like bandaging a hangnail, ignoring the fact that the patient has cancer.
Imagist
He asked a question, your response wasn't an answer, it rude and belittling, and violiated the intent of this web in general. Other than that, see Wirth's Law,and understand both data structures, and Object oriented programming only preperations for Analysis of Algorithms. Analysis of efficiency is the core topic surrounding 90% of computer science topics. You may be a coder but if you don't question efficiency you're not doing computer science. The KISS priciple and C++? "C gives you enough rope to hang youself, C++ gives you the chair too." C++ generally isn't the KISS solution.
NoMoreZealots
And on top of that, I wasn't talking to start with, and now you're just picking a fight. Which again, this is not the forum. The computer I program on at work has a dual core an is two orders of magnatude faster than the one had when I started there 18 years ago and basic software, like word processor, runs slower on it than on the ancient piece of shit I had 18 years ago. And sadly that version of Word was capable then of everything I do on a word processor today way back when. Inefficiency is plague on the programming industry. Most people abuse C++ the same way MS does.
NoMoreZealots
A: 

You didn't mention your platform, but in case you use glibc as your standard library, there is GNU extension - asprintf(), that automatically allocate string big enough.

See man asprintf for details.

More universal approach - first call fprintf() to unused stream just to get the returned length, then allocate the string and print to it, like this:

FILE *stream = tmpfile();
char *string;

string = malloc(fprintf(stream, format, param)+1);
sprintf(string, format, param);
qrdl
I a needed it a mutli platform solution: Win32, solaris, AS3, AS4, AS5....interesting function