Sign in to follow this  
Concentrate

Which is better style?

Recommended Posts

Concentrate    181
Which is better style, 1)
string str = convert<string>(123,BASE_16);
where convert has the following prototype :
template<typename ReturnType, typename InputType>
ReturnType convert(const InputType, const size_t base);
or this way : 2)
string str;
convert(123,str,BASE_16);
where the convert function has the following prototype :
template<typename ReturnType, typename InputType>
void convert(const InputType src,ReturnType& dest, const size_t base);
I feel like the second one looks better.

Share this post


Link to post
Share on other sites
Telastyn    3777
I personally favor #1 strongly. Functions exist to take params and return results. Mixing them up in the parameter list is (imo) distasteful.

Share this post


Link to post
Share on other sites
Zipster    2365
It depends. Can the operation fail? It often makes sense to use an output parameter for the result and reserve the return value for indicating success/failure, most often in cases where a) the output itself can't be used to reliably detect success/failure, and b) you can't use exceptions. I prefer #1 when I have a choice, though.

Share this post


Link to post
Share on other sites
theOcelot    498
What on earth do you prefer #2 for? The only time I consider anything like that is when I don't want to copy some big object for a return value, and even then creating and initializing the variable on two lines is annoying.

Share this post


Link to post
Share on other sites
Antheus    2409
Quote:
Original post by theOcelot
What on earth do you prefer #2 for? The only time I consider anything like that is when I don't want to copy some big object for a return value, and even then creating and initializing the variable on two lines is annoying.


One would use #2 when trying to avoid redundant heap allocations when parsing a lot of text, perhaps hundreds of thousands of lines, thereby reducing running time by a factor of 10.

YMMV, depends on implementation of std::string and whether RVO/NRVO can handle objects which invoke new in constructor.

Share this post


Link to post
Share on other sites
Zahlman    1682
If you really expect to need #2 in specific circumstances for performance reasons, you can always implement #1 in terms of #2, and provide both:


// Ugly version for people who have identified a need
template<typename ReturnType, typename InputType>
void convert(const InputType& src, ReturnType& dest, const size_t base) {
// evil conversion logic
}

// Pretty version for people who like pretty code
template<typename ReturnType, typename InputType>
ReturnType convert(const InputType& src, const size_t base) {
ReturnType result;
convert(src, result, base);
return result;
}

Share this post


Link to post
Share on other sites
theOcelot    498
Quote:
Original post by Antheus
Quote:
Original post by theOcelot
What on earth do you prefer #2 for? The only time I consider anything like that is when I don't want to copy some big object for a return value, and even then creating and initializing the variable on two lines is annoying.


One would use #2 when trying to avoid redundant heap allocations when parsing a lot of text, perhaps hundreds of thousands of lines, thereby reducing running time by a factor of 10.


Sure, other efficiency issues. But Concentrate seems to prefer it aesthetically. That's what I don't get.

Share this post


Link to post
Share on other sites
Fenrisulvur    186
In the given example, I don't really like either very much. What do you gain from using generic semantics in this operation? Seems pointless to me.

Definitely #1, though.

Share this post


Link to post
Share on other sites
Ftn    462
If function can fail without throwing exception, I'd prefer to describe it in function name like:
bool try_convert_in_place(...)
I usually go what Zahlman suggested. If performance is issue at given point, call the faster one.

Share this post


Link to post
Share on other sites
iMalc    2466
Quote:
Original post by Antheus
Quote:
Original post by theOcelot
What on earth do you prefer #2 for? The only time I consider anything like that is when I don't want to copy some big object for a return value, and even then creating and initializing the variable on two lines is annoying.


One would use #2 when trying to avoid redundant heap allocations when parsing a lot of text, perhaps hundreds of thousands of lines, thereby reducing running time by a factor of 10.

YMMV, depends on implementation of std::string and whether RVO/NRVO can handle objects which invoke new in constructor.
I would have thought it made little difference. Doesn't RVO just work out if it's possible to construct the result directly in-place, bypassing the need for a copy-constructor call, for where the function is called/inlined? Oh I see, perhaps it has to consider the possible side-effects of the 'new' call.

With RVO, number 1 can in theory be marginally faster than number 2, assuming that a constructor other than the default one happens to be what is used inside 'convert'. That of course isn't possible in number 2 since the string variable has already been default constructed prior to the call.

In other words, number 1 wins for aesthetic reasons and also don't think that all optimisation reasons are in favour of number 2. One would hope that compilers will get even better over time, not worse! So, overall number 1 certainly wins in my books.
I'd only change it if and when I see it being a performance hot-spot during later optimisation, and even then, the actual change might not be to anything like number 2.

Share this post


Link to post
Share on other sites
phresnel    953
These days I am absolutely used to have all my functions in the form "fun(input) -> output", i.e. usually no parameter gets mutated, and output really is output. That way, you no longer struggle with thinking about which parameters are [in], and which are [out]. When I need to return multiple values, I do either by returning a class- or aggregrate-type, or in trivial cases by using boost::tuple<>.

Note that thanks to RVO, you usually have no performance bottleneck, and even if, C++0x will mostly fix this by move-semantics.

Finally, one of the reasons to use that style was const-correctness, i.e. in your #2, you can't say const string str; convert(123,str,BASE_16);, so you force clients of convert to introduce mutable state (a.k.a. "hm, will that value be changed in this function *skim...waste time...*") where absolutely not necessary.

Share this post


Link to post
Share on other sites
Wouldn't it be better to use a third option?

string str(convert<string>(123,BASE_16));


I'm fairly new to C++ Programming (<2 years), but all the books I've been reading say it's best to initialise something using the constructor if you can, rather than declaring it and using the copy constructor.

If what I've just written is garbage, then someone please tell me why.. :o)

Share this post


Link to post
Share on other sites
nobodynews    3126
Quote:
Original post by BattleMetalChris
I'm fairly new to C++ Programming (<2 years), but all the books I've been reading say it's best to initialise something using the constructor if you can, rather than declaring it and using the copy constructor.
I'm pretty sure both ways use the copy constructor (string a = another_string; and string a(another_string); both use the copy constructor) so I'm not sure what you or your book(s) meant.

Share this post


Link to post
Share on other sites
phresnel    953
Quote:
Original post by BattleMetalChris
Wouldn't it be better to use a third option?

string str(convert<string>(123,BASE_16));


I'm fairly new to C++ Programming (<2 years), but all the books I've been reading say it's best to initialise something using the constructor if you can, rather than declaring it and using the copy constructor.

If what I've just written is garbage, then someone please tell me why.. :o)


It is the same. When you "assign" to a variable X in the declaration of variable X, then it is just syntactic sugar for using the "()" syntax. Note though that there is a subtlety when there are no parameters to the constructors: The compiler will than assume it is a function declaration (google "c++ most vexing parse").

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this