views:

1471

answers:

12

I'm trying to use std::string instead of char* whenever possible, but I worry I may be degrading performance too much. Is this a good way of returning strings (no error checking for brevity)?

std::string linux_settings_provider::get_home_folder() {
    return std::string(getenv("HOME"));
}

Also, a related question: when accepting strings as parameters, should I receive them as const std::string& or const char*?

Thanks.

+24  A: 

Return the string.

I think the better abstraction is worth it. Until you can measure a meaningful performance difference, I'd argue that it's a micro-optimization that only exists in your imagination.

It took many years to get a good string abstraction into C++. I don't believe that Bjarne Stroustroup, so famous for his conservative "only pay for what you use" dictum, would have permitted an obvious performance killer into the language. Higher abstraction is good.

duffymo
Thanks. I was a bit afraid it was considered bad practice, but I'm glad to see it isn't :-)
Pedro d'Aquino
ShoeLace
"It took many years to get a good string abstraction into C++."IMHO it still sucks.
kotlinski
How so? Still an improvement over char *.
duffymo
I don't think that allowing the perfect to be the enemy of the good is a wise strategy. Waiting for perfect software isn't the answer.
duffymo
+5  A: 

Seems like a good idea.

If this is not part of a realtime software (like a game) but a regular application, you should be more than fine.

Remember, "Premature optimization is the root of all evil"

kkaploon
+2  A: 

I agree with duffymo. You should make an understandable working application first and then, if there is a need, attack optimization. It is at this point that you will have an idea where the major bottlenecks are and will be able to more efficiently manage your time in making a faster app.

Brian
+1  A: 

I agree with @duffymo. Don't optimize until you have measured, this holds double true when doing micro-optimizations. And always: measure before and after you've optimized, to see if you actually changed things to the better.

JesperE
+3  A: 

In your case Return Value Optimization will take place so std::string will not be copied.

Kirill V. Lyadvinsky
That's not true. std::string is going to dynamically allocate a buffer and copy the entire string, and return value optimization will not do a lick here. However, he should still use std::string. After checking that getenv() didn't return NULL, that is!
Tom
One allocation will be really. I mean, that would not be copied string itself.
Kirill V. Lyadvinsky
+1: You're correct. Without the RVO, it would have to allocate two buffers and copy between them.
James Hopkin
+1  A: 

Return the string, it's not that big of a loss in term of performance but it will surely ease your job afterward.

Plus, you could always inline the function but most optimizer will fix it anyways.

Gab Royer
+4  A: 

Beware when you cross module boundaries.

Then it's best to return primitive types since C++ types are not necessarily binary compatible across even different versions of the same compiler.

Hans Malherbe
You need to do much more than just avoid C++ return types for that... you need to completely pimplize *all* C++ code to really be safe, at which point you're going to be creating a C wrapper on top of your existing codebase anyways, due to the nature of class declarations.
Tom
+1  A: 
Faisal Vali
+4  A: 

Return the string, like everyone says.

when accepting strings as parameters, should I receive them as const std::string& or const char*?

I'd say take any const parameters by reference, unless either they're lightweight enough to take by value, or in those rare cases where you need a null pointer to be a valid input meaning "none of the above". This policy isn't specific to strings.

Non-const reference parameters are debatable, because from the calling code (without a good IDE), you can't immediately see whether they're passed by value or by reference, and the difference is important. So the code may be unclear. For const params, that doesn't apply. People reading the calling code can usually just assume that it's not their problem, so they'll only occasionally need to check the signature.

Steve Jessop
A: 

The cost of copying strings by value varies based on the STL implementation you're working with:

  • std::string under MSVC uses the short string optimisation, so that short strings (< 16 characters iirc) don't require any memory allocation (they're stored within the std::string itself), while longer ones require a heap allocation every time the string is copied.

  • std::string under GCC uses a reference counted implementation: when constructing a std::string from a char*, a heap allocation is done every time, but when passing by value to a function, a reference count is simply incremented, avoiding the memory allocation.

In general, you're better off just forgetting about the above and returning std::strings by value, unless you're doing it thousands of times a second.

re: parameter passing, keep in mind that there's a cost from going from char*->std::string, but not from going from std::string->char*. In general, this means you're better off accepting a const reference to a std::string. However, the best justification for accepting a const std::string& as an argument is that then the callee doesn't have to have extra code for checking vs. null.

jskinner
Wouldn't this mean I'm better off accepting a const char*? If my client has a std::string he can c_str() it, which, as you said, doesn't cost much. On the other hand, if he has a char*, he's forced to build a std::string.
Pedro d'Aquino
Brian: GCC most certainly does use a reference counted string implementation, have a read of /usr/include/c++/4.3/bits/basic_string.h, for example.
jskinner
Pedro: If you're writing a function that only needs a const char*, then yes, you're clearly better off accepting a const char*. If the function needs it as a std::string, then it's better off as that. My comment was more in relation to the cases where you don't know which you need (e.g., when writing an interface class).
jskinner
@Brian - RTFCode, it's plain as day. GCC still uses reference-counting.
Tom
Wow, I was totally wrong. Sorry about that. I recall reading an in-depth article about the failures of reference counted strings, and how that it is actually more efficient to go with a non-referenced counted solution. I must have dreamed it all.
Brian Neal
+1  A: 

If you pass a referenced string and you work on that string you don't need to return anything. ;)

Partial
A: 

It's human nature to worry about performance especially when programming language supports low-level optimization. What we shouldn't forget as programmers though is that program performance is just one thing among many that we can optimize and admire. In addition to program speed we can find beauty in our own performance. We can minimize our efforts while trying to achieve maximum visual output and user-interface interactiveness. Do you think that could be more motivation that worrying about bits and cycles in a long run... So yes, return string:s. They minimize your code size, and your efforts, and make the amount of work you put in less depressing.

AareP