So... C++14 is done :O

Started by
84 comments, last by BitMaster 9 years, 8 months ago

Range based loops, however, added nothing. The old method was still there, and it is still there. The result is that instead of the traditional 'minimalist' approach, there is duplication. It did not enable any new thing. It did not add a feature. It did not do something that could not be trivially done before. It obscures details, adds an additional interface, but doesn't add any functionality. It is syntactic sugar, it is language bloat.

Range-based for loops basically implemented for-each loops, which in my book is good enough to warrant it. In my personal opinion, I totally love them. Sure, you could possibly do the same thing with a macro before, but its much cleaner that way:


std::vector<Class*> vValues;

for(auto pValue : vValues)
{
    pValue->DoSomething();
}

for(auto itr = vValues.begin(); itr = vValues.end(); ++itr)
{
    (*itr)->DoSomething(); // i totally loved having to do that itr-dereferencing as well before on vector<pointer>
}

I see your argument about not implementing something totally new, but fail to see why this is a bad thing. Everything that allows you to write code faster and cleaner at the same time, while not being forced upon, is IMHO a decent thing. Why would anyone ever prefer to write the loop the second way (and thats the nice version already using "auto")? Unless you want to delete something from the loop, yeah, quess that counts.

Advertisement
Why would you write the loop the 2nd way when you have std::for_each and lambda functions?


Why would you write the loop the 2nd way when you have std::for_each and lambda functions?

You don't, unless you don't know about std::for_each like I did.


std::vector<Class*> vValues;

std::for_each(vValues.begin(), vValues.end(), [] (Class* pValue)
{
     pValue->DoSomething();
});

I quess that works, especially if you make a wrapper function that removes the need for always specifiying "begin/end" when all you want is the full range. Quess I still prefer range-based loops, just a little more explicit than this version. (I do have to admit that this changes things a little bit at least, always more to learn :D).

C++14 would frame that more like;

std::for_each(std::begin(Values), std::end(Values), [](auto value)
{
    value->DoAThing();
});
and once you get use to reading that then there is always this fun setup...


std::erase(std::remove_if(std::begin(values), std::end(values), [](auto value) { return !value->alive();}), std::end(values));
smile.png
Why would you use any of those examples when the idiomatic version from the past 2 or 3 decades still works, is understood by everyone, and generates the same ASM? :lol:
std::vector<Class*> vValues;
for( int i=0, end=vValues.size(); i!=end; ++i )
    vValues[i]->DoSomething();
I agree with Frob's post on language bloat. New features are nice, but duplicated/redundant features for the sake of being modern are unecessary.

nullptr is just about the only feature of C++11 I actually use (though I was fine with the plain-old NULL). Ctr delegation is also nice, but again - syntactic sugar.

Seems to me like C++11/14 features are mostly beneficial if you are writing an STL like library (See Bjorn's FAQ, a lot of the examples are STL related).

I agree with frob - C++11 and C++14 are moving away from the minimalist approach, which isn't a good thing (and don't get me started on the dangers of 'auto').

I find many of the C++11 features 'tacked' on and very hackish as is, so I'm actually dreading C++14 a bit.


Why would you use any of those examples when the idiomatic version from the past 2 or 3 decades still works, is understood by everyone, and generates the same ASM? laugh.png

Lots of things from the past still works, which still doesn't mean its the most optimal way of doing things. One can still send letters for written communication, but using online services is just a tad bit quicker ;)

Also while probably most people understand the old version, doesn't mean its easy to read. In fact, let alone the different variants, like having to explicitely store the end-condition and post/pre-increment validates a fixed solution for me.

More prone to error comes to mind, too. Especially for nested loops. Have lost count of how many times I mistakenly incremented the wrong variable or some stuff like that.

And as I already mentioned: Less code to type each time around - for the cost of what? That someone who hasn't seen this kind of loop might have to get used to reading it? From my personal view, the range-based loop is way easier to read, especially if you are new to the language - would anyone want to argue that a beginner would have an easier time with the old explicit loop?

Although generally, based on the old/new discussion, the question shouldn't be "what do I gain by using the new way" but rather "what do i lose by doing so?". People tend to favor that which they are used to, so unless there is a huge loss and virtually no gain for doing it with a new option, I'd say pick the new one.

EDIT:


nullptr is just about the only feature of C++11 I actually use (though I was fine with the plain-old NULL). Ctr delegation is also nice, but again - syntactic sugar.

Varadic templates are also very useful. Reduces code complexity on things like signal/slots, delegates etc... by a drastic amount, also allowing for perfect forwarding.


Although generally, based on the old/new discussion, the question shouldn't be "what do I gain by using the new way" but rather "what do i lose by doing so?". People tend to flavor that which they are used to, so unless there is a huge loss and virtually no gain for doing it with a new option, I'd say pick the new one.

I actually think the question is "in how many ways can someone else screw-up the code?". And in C++11 the answer is a lot more then with the "old" C++.

If you are an experienced programmer, who understands the pros and cons of the new feature - then use whatever you want. The problem is that there are way too many inexperienced programmers who (unintentional?) abuse things, or will understand what you are doing.

Take 'auto' for example - it's great when used with caution (and very very sparsely). But I saw some programmers who just decided that it would be great to use it as much as possible (even a very experienced one), regardless of minor things like code readability and type safety.

[EDIT] - 'type safety' should be 'compile time type checks'.

C++ is not a scripting language, nor is it a high-level abstracted language with powerful RTTI like Java. And it shouldn't be. Most of the new features seem to solve very minor problems and do not provide great benefit over the legacy C++.

Regarding the different ways of writing a loop that iterates through a vector, I prefer using indices most of the time, because it's the easiest to modify in the future.

For instance, let's start with code similar to Hodgman's:
for (size_t i = 0, end = vValues.size(); i != end; ++i)
  vValues[i]->DoSomething();

What if I only want to DoSomething on elements that pass some test?
for (size_t i = 0, end = vValues.size(); i != end; ++i) {
  if (some_test(*vValues[i]))
    vValues[i]->DoSomething();
}

What if I need to add more elements to the vector in some circumstances?
for (size_t i = 0; i != vValues.size(); ++i) {
  vValues[i]->DoSomething();
  if (some_circumstances(*vValues[i]))
    vValues.push_back(some_new_thing); // Iterators are now invalid, but indices still work just fine
}

Try to do that with any of the other styles. smile.png

For very simple loops, the range-based format is very clean and I sometimes use it.

This topic is closed to new replies.

Advertisement