I was given this piece of code, which calculates the length of the longest string
in a vector
of string
s:
static size_t max_line_length(std::vector<std::string> &lines) {
size_t max = 0;
for (auto it = lines.begin(); it != lines.end(); it++) {
if (it->length() > max) {
max = it->length();
}
}
return max;
}
I am new to C++ with a significant background in Java. If I would write such a function myself, I would come up with something like:
static size_t max_line_length(std::vector<std::string> lines) {
size_t max = 0;
for (auto line : lines) {
if (line.length() > max) {
max = line.length();
}
}
return max;
}
The difference is in the use of pointers, and the way in iterating the string
s.
Is there a significant performance difference between these implementations, or are there best practices involved in this?
2 Answers 2
The first version of the algorithm uses a traditional C++03-era for
loop with iterators. The only modern element is the auto
used to deduce an std::vector<std::string>::iterator
. The second loop uses a C++11 range-based for
loop whose syntax is close to the one used in Java. The range-based for
loop is now preferred for several reasons:
Its terse syntax (when iterators are fully spelled out, a traditional
for
loop is ugly).Its genericity: a range-based
for
loop also works with C arrays andstd::valarray
.end
is automatically cached instead of being evaluated at each iteration.
That's it for the for
loops: the range-based for
loop is preferred. However, there are some things that could be improved in your second version:
You should pass
lines
as aconst
reference. When you don't need to modify an instance, aconst
reference is good since it avoids a useless copy.In your range-based
for
loop, you should writeconst auto&
since you don't modifyline
either. It currently performs many useless copies of fullstd::string
s just to get their size. Actually, the best thing to write in range-basedfor
loops is generallyauto&&
, but the explanation may be a little complicated since it involves lvalues, rvalues,const
-correctness and type deduction.
This is more C++-like:
struct size_less
{
template<class T> bool operator()(T const &a, T const &b) const
{ return a.size() < b.size(); }
};
static size_t max_line_length(std::vector<std::string> const &lines)
{
return std::max_element(lines.begin(), lines.end(), size_less())->size();
}
-
\$\begingroup\$ What is
Base
? Why use a template? Why not use a lambda?lines
should beconst
. Free functionsbegin
andend
should be favored over member functionsbegin
andend
. Using the standard library is a very good point though. \$\endgroup\$nwp– nwp2014年12月06日 23:19:58 +00:00Commented Dec 6, 2014 at 23:19 -
\$\begingroup\$ @nwp: Sorry for the
Base
, it was left over from another suggestion I was going to give but then decided not to. I improved the function withconst
, thanks. As for why not lambdas?: because they bloat the generated code for no good reason. Every lambda has a new type, even if it has the same body -- thus every lambda generates new code, which increases compile times and bloats the output file for no good reason. Not to mention that this is C++03-compatible which I prefer (and that's why I didn't use the free versions ofbegin
andend
). \$\endgroup\$user541686– user5416862014年12月07日 00:14:36 +00:00Commented Dec 7, 2014 at 0:14 -
\$\begingroup\$ Lambdas bloat the generated code no more than a
size_less
class created to be used in one specific place and they allow for more expressive local function objects. \$\endgroup\$Morwenn– Morwenn2014年12月07日 10:32:19 +00:00Commented Dec 7, 2014 at 10:32 -
\$\begingroup\$ @Morwenn: No, the entire point of
size_less
is that it can be used in more than one specific place. Although I'm sure you already knew this. \$\endgroup\$user541686– user5416862014年12月07日 10:50:31 +00:00Commented Dec 7, 2014 at 10:50 -
\$\begingroup\$ @Mehrdad But will there ever that many places where it will be needed? That's the whole point. \$\endgroup\$Morwenn– Morwenn2014年12月07日 10:53:47 +00:00Commented Dec 7, 2014 at 10:53
Explore related questions
See similar questions with these tags.
auto
toconst auto&
in the loop, otherwise every line will be needlessly copied. \$\endgroup\$const std::vector<std::string> &lines
as well? Also, if you could write your comment in a nice little answer, I can accept it :) \$\endgroup\$vector
would be a constant, but not thestring
s themselves, right? So this would allow the function to manipulate thestring
s, whereas the original method would be pure. \$\endgroup\$