Jump to content

  • Log In with Google      Sign In   
  • Create Account

Is C++ too complex?


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
122 replies to this topic

#1 Kyall   Members   -  Reputation: 287

Like
2Likes
Like

Posted 30 November 2012 - 01:42 AM

I always want to improve my C++ knowledge and this time around this means finding out what parts of C++ aren't any good, so I thought I'd field a question to the experts: what parts of the c++ language are too complex to the point they interfere with writing good code and should be avoided as much as possible. Should I always use the stdio and not iostream for example, dynamically allocated memory in classes vs putting it in structs. What's the debate on what parts of c++ improve code, and the other parts that are over complicated and are damaging to code standards.
I say Code! You say Build! Code! Build! Code! Build! Can I get a woop-woop? Woop! Woop!

Sponsor:

#2 BitMaster   Crossbones+   -  Reputation: 4427

Like
6Likes
Like

Posted 30 November 2012 - 02:00 AM

There are no 'bad' places of C++. C++ is a toolbox with a lot of tools in it, each more or less suitable for particular jobs. The merits of a good programmer are the ability to pick the right tool for each particular job (actually a really good programmer would not limit themselves to just C++, but let's stay with just that language for the purpose of this thread).

If I wanted to parse a small text file every two hours I would certainly not use C style file IO over iostreams. If the whole purpose of my program were chewing through Gigabytes of text files I would use neither explicitly, I would have a look at flex/bison, Antlr or their friends to see which suited my needs best.

#3 LorenzoGatti   Crossbones+   -  Reputation: 2762

Like
4Likes
Like

Posted 30 November 2012 - 02:23 AM

What's the debate on what parts of c++ improve code, and the other parts that are over complicated and are damaging to code standards.

C++ is full of subtle and complex features, but they are only "overcomplicated" relative to incompetent users, not relative to their purpose; there are many good reasons to do things in a certain way, and valid use cases for everything you don't like or understand.
Produci, consuma, crepa

#4 solenoidz   Members   -  Reputation: 531

Like
2Likes
Like

Posted 30 November 2012 - 02:28 AM

dynamically allocated memory in classes vs putting it in structs.


I'm not sure what you mean by that. Maybe stack vs heap ?

#5 Steve_Segreto   Crossbones+   -  Reputation: 1551

Like
2Likes
Like

Posted 30 November 2012 - 02:49 AM


dynamically allocated memory in classes vs putting it in structs.


I'm not sure what you mean by that. Maybe stack vs heap ?


I believe he means that member data of a class is either dynamically allocated and referenced with a pointer or else it isn't (in which case it may be global, stack or still dynamically allocated, depending on how the instance of the class was defined).

#6 Hodgman   Moderators   -  Reputation: 31799

Like
14Likes
Like

Posted 30 November 2012 - 02:54 AM

what parts of the c++ language are too complex to the point they interfere with writing good code and should be avoided as much as possible.

goto


[edit]and volatile[/edit]

Edited by Hodgman, 06 December 2012 - 08:46 PM.


#7 BitMaster   Crossbones+   -  Reputation: 4427

Like
0Likes
Like

Posted 30 November 2012 - 02:58 AM

While I personally hope that I never have to deal with goto myself, I have encountered enough "damned if I do, damned if I don't" scenarios to understand that I might be at some point in a situation where goto might be the least evil way to solve something. I hope I won't have to ever use it though - no amount of showers would be enough to ever feel clean again after that.

#8 L. Spiro   Crossbones+   -  Reputation: 14232

Like
4Likes
Like

Posted 30 November 2012 - 02:58 AM

dynamically allocated memory in classes vs putting it in structs.

Classes and structures are exactly the same thing except for default visibility of members and methods. You are asking about 2 unrelated things—whether related information is inside classes or structures does not matter, nor does it matter if it was allocated dynamically or embedded within an encapsulating class/struct. There are combinations of these 2 things suitable for various situations, and there is a time and place for all of these combinations.

It is just common practice to make structures hold “plain old data”, but otherwise there is nothing unique between classes and structures.


The only part of C++ that should be avoided as much as possible is “goto”.
[EDIT]
Damn it Hodgman, beat me to it.
[/EDIT]


L. Spiro

Edited by L. Spiro, 30 November 2012 - 02:59 AM.

It is amazing how often people try to be unique, and yet they are always trying to make others be like them. - L. Spiro 2011
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
I went to my local Subway once to find some guy yelling at the staff. When someone finally came to take my order and asked, “May I help you?”, I replied, “Yeah, I’ll have one asshole to go.”
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums

#9 Álvaro   Crossbones+   -  Reputation: 13901

Like
13Likes
Like

Posted 30 November 2012 - 03:35 AM

Although I agree that there are valid uses cases for everything in the language, I mostly restrict myself to the subset of the language that I believe every C++ programmer will understand, because code should be written primarily to be read by other programmers.

Some examples:
  • I use inheritance very infrequently. When I do, I only use single public inheritance and only for the purpose of using virtual dispatch, and I always provide a factory function that creates the actual objects (this is also about the only place where I would write `new' in a program, which is wrapped in a smart pointer right away). The rest of the code is not allowed to know about the specific subclasses.
  • I don't use RTTI.
  • I only overload operators when defining mathematical classes, and the occasional operator << or >> for streams.
  • I don't use trivial standard algorithms (e.g., std::copy), because loops are much easier to read, especially with C++11.
  • I don't make complicated template structures, preferring to do some things at run time that could be done at compile time, because it usually helps the clarity of the program.

I am not as adverse to goto as others are here. I learned programming in the 80s and I wrote my share of goto-packed nightmare programs in BASIC. I don't recommend this to anyone, but it helps me tell the difference between a goto that shows poor understanding of loops and function calls (the vast majority of gotos beginners would use) and one that is clear. There are two types of goto that are so useful and so harmless that they were given special names: `break' and `continue'. Using goto to break out of a loop from within a switch statement, for instance, seems perfectly fine to me. I'll write the code in some other way if I think it's more clear, but only then.

Edited by Álvaro, 30 November 2012 - 03:38 AM.


#10 Bluefirehawk   Crossbones+   -  Reputation: 1232

Like
5Likes
Like

Posted 30 November 2012 - 03:42 AM

The language itself is to me very beautiful. But it is complex and the programmer requires more knowledge on how the computer system works, compared to a Java/.Net/Perl programmer.
ome stuff doesn't make much sense anymore in the modern C++11 standard, like having structs and classes, which essentially are the same today. I guess they are still around for backwards compatibility.

I think the nasty bit of C++ isn't the language, it is everything around it. Most toolchains for C++ are old, very old, and seem to be deliberately complicated. I spent so much time crawling through the internet, getting my cross platform build script to make a platform dependent build script to build my project. Yet, my project is still not glued to unit tests.
Comparing it to the java, you have far easier toolchains, designed for modern standards of development. And you almost get platform indipendence for free.
Project: Project
Setting fire to these damn cows one entry at a time!

#11 Kyall   Members   -  Reputation: 287

Like
0Likes
Like

Posted 30 November 2012 - 04:28 AM

All good answers guys, it was nice to read every single post confirming my biases that there's nothing unnecessary in the language, next time I read an article that has me challenge my assumptions about c++ I'll ignore it. Also using a subset for clarity seems like a good idea.
I say Code! You say Build! Code! Build! Code! Build! Can I get a woop-woop? Woop! Woop!

#12 Karsten_   Members   -  Reputation: 1655

Like
1Likes
Like

Posted 30 November 2012 - 05:10 AM

The parts of C++ that should generally be avoided (unless necessary) is misusing C stuff rather than the C++ alternative.
For example fopen, malloc and goto could be replaced with ifstream, new (with smart pointer) and exception respectively.

Whilst the ability to use classic C stuff seems to make the language complex, I actually prefer the way C++ extends rather than reinventing the whole language again from scratch (such as C#).

Kindof like OpenGL is seemingly quite hard to learn for new developers because it still has all the old stuff rather than dropping it all and starting with a brand new graphics API.

Mutiny - Open-source C++ Unity re-implementation.
Defile of Eden 2 - FreeBSD and OpenBSD binaries of our latest game.


#13 NightCreature83   Crossbones+   -  Reputation: 3032

Like
1Likes
Like

Posted 30 November 2012 - 06:26 AM

The parts of C++ that should generally be avoided (unless necessary) is misusing C stuff rather than the C++ alternative.
For example fopen, malloc and goto could be replaced with ifstream, new (with smart pointer) and exception respectively.

Whilst the ability to use classic C stuff seems to make the language complex, I actually prefer the way C++ extends rather than reinventing the whole language again from scratch (such as C#).

Kindof like OpenGL is seemingly quite hard to learn for new developers because it still has all the old stuff rather than dropping it all and starting with a brand new graphics API.

how would you replace the goto in this bit with an exception
for (int bar =0; bar < 100; ++bar)
{
	 for(int foo = 0; foo < 100; ++foo)
	 {
	 	 if (foo * bar == 100)
	 	 {
	 	 	 goto loopBreak;
	 	 }
	 }
}

loopBreak:
	 printf("%d", 100);

The code I am presenting is not doing something usefull at all to be honest but imagine a difficult calculation going on over a grid in which if a certain condition is met you need to break out of both loops and continue the rest of the algorithm with the results already calucalted?
Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, Mad Max

#14 Bacterius   Crossbones+   -  Reputation: 9267

Like
2Likes
Like

Posted 30 November 2012 - 06:40 AM

how would you replace the goto in this bit with an exception

[source lang="cpp"]int doWork(){ for (int bar =0; bar < 100; ++bar) { for(int foo = 0; foo < 100; ++foo) { if (foo * bar == 100) { return 1; } } } return 0;}// ...if (doWork()) printf("%d", 100);[/source]

Or, use a boolean flag for each loop... works too but it's ugly.

EDIT: I guess foo wasn't the best function name, lol.

Edited by Bacterius, 30 November 2012 - 07:02 AM.

The slowsort algorithm is a perfect illustration of the multiply and surrender paradigm, which is perhaps the single most important paradigm in the development of reluctant algorithms. The basic multiply and surrender strategy consists in replacing the problem at hand by two or more subproblems, each slightly simpler than the original, and continue multiplying subproblems and subsubproblems recursively in this fashion as long as possible. At some point the subproblems will all become so simple that their solution can no longer be postponed, and we will have to surrender. Experience shows that, in most cases, by the time this point is reached the total work will be substantially higher than what could have been wasted by a more direct approach.

 

- Pessimal Algorithms and Simplexity Analysis


#15 Hodgman   Moderators   -  Reputation: 31799

Like
3Likes
Like

Posted 30 November 2012 - 06:46 AM

how would you replace the goto in this bit with an exception

I'm of the opinion that exceptions as implemented in C++ are too costly to be used in the same fashion as they are in C#/Java. I use exceptions in C#, but never ever use them in C++. </opinion>

Anyway, as above you can split that work out into a function, or just put your condition into the for loops:
void function()
{
  found = false;
  for (int bar =0; !found && bar < 100; ++bar)
    for(int foo = 0; !found && foo < 100; ++foo)
      if (foo * bar == 100)
        found = true;
}
Pretty much the only time I use goto is when you've got a complex function that's allocating multiple resources and has multiple points of failure, where they all goto a cleanup section at the bottom. However, RAII solves this in C++, so it's not necessary any more, most of the time.

 [edit]
Out of interests sake, because I assumed they'd all generate pretty much the same Asm, I tested my C++ compiler (MSVC9 /O2) with the above loop+flag, the previously posted function+return, and the original goto-as-double-break variants. In all cases the loop+flag was the slowest, so I'll normalize the results against it and call it's speed 100%.
If the break condition is hit quickly (e.g. foo*bar == 100), then the function+return solution finished in 94% of the time, and the goto in 92% of the time. If the break condition isn't hit (e.g. foo*bar == 99999), then function+return finished in 67% of the time, and goto in 99% of the time...
[edit2]Added a 4th test for throwing a bool to escape the two loops. If the condition isn't met, it weighed in at 103%, but if the condition is met quickly as before, it took 206358% as long...
So, uh, yeah, I'd go with Bacterius' code.

Edited by Hodgman, 30 November 2012 - 07:31 AM.


#16 Telastyn   Crossbones+   -  Reputation: 3730

Like
6Likes
Like

Posted 30 November 2012 - 06:47 AM

All good answers guys, it was nice to read every single post confirming my biases that there's nothing unnecessary in the language, next time I read an article that has me challenge my assumptions about c++ I'll ignore it.


That is foolish. The articles that challenge our assumptions are the most important for us to read. Too many developers fall into dogmatic faith that what they know is best, ignoring better solutions. This is one of the quickest ways to become a bad programmer.

While there aren't many unnecessary parts of C++ there are many parts that should be avoided, and far more that require great care to use properly. The language itself is a poor option for many programming problems.


#17 Bregma   Crossbones+   -  Reputation: 5427

Like
2Likes
Like

Posted 30 November 2012 - 08:06 AM

I'm of the opinion that exceptions as implemented in C++ are too costly to be used in the same fashion as they are in C#/Java. I use exceptions in C#, but never ever use them in C++.

It's funny, because ,y gut feel puts me in the same position with many constructs. Using dictionaries or regular expressions in Python, for example, is normal but in C++ I tend to avoid them because they're expensive.

Funny thing is, much of the time such constructs in higher-level languages are implemented using the underlying C++ construct. For instance, Java exceptions in the GCC Java runtime are implemented using exactly the same mechanism as C++ exceptions (it's the same libgcc_s.so file on my system). Any performance barrier is psychological: Java forces you to pay the cost always by design, C++ allows you to pay only for what you use, and you can avoid using exceptions, so you feel guilty about waste.

I am still of the opinion that exceptions are too costly to use for anything but exceptional situations. I limit (but not avoid) their use in C++, avoid Java completely, and use Python mostly for prototyping.
Stephen M. Webb
Professional Free Software Developer

#18 Bluefirehawk   Crossbones+   -  Reputation: 1232

Like
-2Likes
Like

Posted 30 November 2012 - 08:14 AM

The code I am presenting is not doing something usefull at all to be honest but imagine a difficult calculation going on over a grid in which if a certain condition is met you need to break out of both loops and continue the rest of the algorithm with the results already calucalted?

I would say wrong semantic. Since you loop as long as a condition is met, you should need a while loop. Breaking out of a for loop is a strong indicator for that.

It is a bit nitpicky, but from a theoretical computer science stand point, for loop with a break statement is wrong. A for loop is intended to repeat the internal statement for a known amount. Therefore a for loop can be expanded by repeating the line of code by x amount of time.

A while loop is very different, each while loop has a variance and invariance which you can use to proof your loop aborts, and with the invariance you can proof that your loop calculates what it should.
</detail>

I am sure there is a freak case where a goto statement makes more sense and is more readable than any other solution, But I have yet to see a good example for it.
You can live a happy and productive life writing clean code without ever using a goto statement.

Edited by Bluefirehawk, 30 November 2012 - 08:14 AM.

Project: Project
Setting fire to these damn cows one entry at a time!

#19 Bregma   Crossbones+   -  Reputation: 5427

Like
0Likes
Like

Posted 30 November 2012 - 08:36 AM

I am sure there is a freak case where a goto statement makes more sense and is more readable than any other solution, But I have yet to see a good example for it.
You can live a happy and productive life writing clean code without ever using a goto statement.

In C++. The assertion is not transitive to C.
Stephen M. Webb
Professional Free Software Developer

#20 Hodgman   Moderators   -  Reputation: 31799

Like
1Likes
Like

Posted 30 November 2012 - 09:17 AM

It's funny, because ,y gut feel puts me in the same position with many constructs. Using dictionaries or regular expressions in Python, for example, is normal but in C++ I tend to avoid them because they're expensive.

Yeah I get the same feelings, in C# a dictionary is common for me, but I never use std::map in C++, and a hash-table is almost always implemented on top of a flat array... but this is because I'm writing real-time systems in C++ and bloated tools in C#.

Any performance barrier is psychological: Java forces you to pay the cost always by design, C++ allows you to pay only for what you use, and you can avoid using exceptions, so you feel guilty about waste.

No, exceptions in C++ are a fundamentally different construct than exceptions in Java, they just happen to share terminology. Plus most C++ compilers suck at implementing their flavour of them, while the JVM is good at it's flavour. If you port my benchmarks to Java, there's no way the throw version of the double-break idiom will be 2000x slower than the other implementations.

Edited by Hodgman, 30 November 2012 - 09:24 AM.





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS