tags:

views:

914

answers:

11
+14  Q: 

Thinking in C++?

The programming language I use has been Java. I've been transitioning to C++ which has been somewhat rocky. The "rocky-ness" isn't in the learning but more along the lines of "Thinking in C++".

I've seen many people say that you should learn C first (I technically know it already), and then I see people say no skip C and go straight to C++. Once again this isn't a "learning" problem; it's a "thinking in" problem; I know the syntax to C++, I know OOD in C++, etc.

For example this code in SDL I can explain it as if I know it but I cant really "take advantage" of pointers:

SDL_Surface* hello = NULL;

Should I be programming in C to get "used" to this? What should I be doing to get used to pointers if I've never used them coming from a language such as Java?

+6  A: 

I don't think that learning C will help with your "thinking" in c++". Generally, you just need to get used to certain C++ concepts and why they are useful.

Key ones are smart pointers (more generally RAII) and templates which are huge.

Also keep in mind that c++ is a multi-paradigm language, not strictly OOP. Often the best solution isn't very object oriented at all (the STL is a great example of templates being better design than an object based one).

Evan Teran
What does RAII mean? Do you have any tips on "smart pointers?"
RAII stands for "resource allocation is initialization". Generally speaking it is the concept of using constructors to allocate resources and more importantly using destructors to release resources. smart pointers are a specific implementation of this idiom. It can be applied in lots of ways to write exception safe and generally simpler code.
Evan Teran
My only real advice with smart pointers is "use them" :-). It will save you a lot of grief. There are situations where you'd want to use a raw pointer, but they are becoming more and more rare in real world code.
Evan Teran
I think one should thoroughly understand pointers, indirection, and memory management *before* understanding smart pointers.
BobbyShaftoe
For someone with a Java background, pointers and indirection should just be natural concepts. Java references **are** C++ pointers --without arithmetic. Since you don't use arithmetic with smart pointers, nor you have to manage memory, a `shared_ptr` is as close as it gets to a Java reference --performance aside, determinism aside, need to dereference aside.
David Rodríguez - dribeas
+3  A: 

You know, there's a very well-regarded book that's actually entitled "Thinking in C++" :) Even better, it's free! It should help you grok things like pointers on a deeper level -- it's explicitly geared towards that.

Adrian Petrescu
+13  A: 

It's true that pointers are a big deal, and C and C++ share that concept.

But C++ is not just C with objects.

There are two free books that you can download from Planet PDF by Bruce Eckel called Thinking in C++ (volumes I and II) that will really help you get the sense of C++.

A lot of C++ also is the toolkit, whether it be the standard library (std) or MFC or the classes from the anti-grain geometry library or whatever. That too makes a difference.

If you need C++, go for C++. Learning C first is like learning Spanish so you can learn Portuguese, instead of just aiming for Portuguese.

lavinio
+1 for Eckel's book.
David
Fabio Fracassi
+10  A: 

If you understand the syntax, then the only way to become "fluent" in a language is to use it.

Using C is a good way to keep things simple and get close to the "metal", but it isn't the same as C++, so ultimately I would advise using C++ if you wish tolearn C++. (i.e Don't learn Latin if you want to be fluent in Italian, even though Latin will give you many insights, the two languages are different beasts, and the thought processes involved are correspondingly different)

Pointers are very easy, once you "get" them. A very good idea when using pointers is to use the "p" prefix notation. For each pointer (level of indirection) add a "p" to the front of your variable name to remind you that it is a pointer:

Vehicle vehicle     = an actual vehicle
Vehicle *pVehicle   = a pointer to a Vehicle
Vehicle **ppVehicle = a pointer to a pointer to a Vehicle

To access the vehicle you have to dereference once for each pointer, i.e:

vehicle.SetName("Ford Focus");       // Directly access an object instance
(*pVechicle).SetName("Ford Focus");  // Dereference once
(**ppVehicle).SetName("Ford Focus")  // Dereference twice

There are three ways to dereference (just different syntaxes that generate identical code):

(*pVehicle).DoSomething()
pVehicle->DoSomething()
pVehicle[0].DoSomething()

When you use arithmetic on pointers they operate in Vehicle units, not in bytes, i.e

pVehicle++;   // Move to the next vehicle record, not just the next byte

And finally, for each

pVehicle = new Vehicle

you need to balance your code with:

delete pVehicle;
pVehicle = NULL;

(edit) Oh, and almost forgot the most important one: ALWAYS check that your pointer is valid before you try to use it!

if (pVehicle != NULL)
    ...use pVehicle

I find the "p" notation invaluable as you never forget that something is a pointer, and the number of p's tells you how many dereferences are needed. Once I adopted it, I stopped writing NULL dereference/access violation bugs.

That's all you need to know about pointers. Now you just have to use them a lot to gain fluency.

Jason Williams
I think I like the idea of prefixes with `p`... might start doing that... if I ever go back to C++.
Mark
It does take a bit of getting used to, but once you are accustomed to it, it really clarifies things and reduces mistakes.
Jason Williams
I don't see any point in naming conventions that express semantics already handled by the type system. But if it helps you, knock yourself out...
FredOverflow
Don't always check for null pointers, just check at library boundaries or where a null pointer is a valid concept in the specific cases (for example a pointer to a User who might be anonymous = null). The pointer won't magically lose its value inside your functions.
Malte Clasen
@Fred: The point is that *every* time you use a variable the naming semanitcs tell you *how* it must be used, so you *never* make a mistake. I was skeptical, then I spent a week doing this, and now I find it difficult to understand why anybody avoids using such prefixes (other than confusing them with Hungarian Notation, which is completely useless - I don't need to be reminded of the *type* of a variable, but its *usage* is very important)
Jason Williams
@Malte: Obviously you don't need to check for NULL on *every* access - but if in doubt, checking for NULL wastes one clock cycle while forgetting to check can crash your program and lose your customer's valuable data - so which is the safer approach? I use a lot of ASSERTs so the pointers are verified constantly in debug builds, but only checked at critical "gates" in release builds. If you over-do it with NULL checks, you can always remove some later when your program is robust and your profiler proves that the NULL checks are now the bottleneck (p.s this never happens in real life)
Jason Williams
@Fred: P.S. I also use "i" for index/iterator variables and "m" for member variables, neither of which are supported/handled by the type system. Is this int an iterator: "vehicle". How about "iVehicle"? Aha. In the latter case I don't need any additional context to understand what the name means. That means I code faster and more reliably and make fewer mistakes - this is a measurable, objective, metric and has been proven time and time again.
Jason Williams
@Jason: How is a p prefix not telling you something about the type? And how can you accidentally use a pointer variable in a wrong way? Why use pointers at all, there are almost always better alternatives. And if you cannot immediately tell whether a variable is a local or a member (I hope you don't have too many globals), your function is simply too big. But again, whatever floats your boat. If these conventions help you, then by all means continue to use them.
FredOverflow
@Fred: 1) Make a simple 20 line function with 8 variables declared at the point where they are used, so you have to search up and down 20 lines of code to find where a variable is declared to work out what it is for (Yes, it's easy for *you* to understand, but Software Engineers don't write code for themselves, they write it for their *other team members* to maintain in future).
Jason Williams
2) Copy a line of code "address = base + span * numEntries" and paste it into an email, and then see how many extra lines of code you have to include to describe what those three variables are (are they members? Are they pointers? Are they local? Are they constants? Now, read this and tell me what you think it's doing: pAddress = pBase + cSpan * numEntries;
Jason Williams
3) Dereference this pointer: "obj". How many * characters do you need to dereference it to get the object it points to? Try one. Damn, it doesn't compile. OK, look up to see where it is declared. Is it a local var? No. Is it a parameter? no. Is it a member declared at the top of the file? Maybe at the bottom of the file? Gawd I wish this programmer had given me a clue. OK - so dereference "ppObj" instead ... "**ppObj" - case solved in a *microsecond*.
Jason Williams
4) Write nested loops that enumerate arrays of Cars and Vehicles to find a match. You need the 2 arrays (mCars, vehicles), 2 array indexes (iCars, iVehicles), and you also want to use a pair of temp pointers (pCar, pVehicle). These names clearly describe the variables *and* how to use them, and at the same time, make them unique so we dont get name clashes. So instead of "cars,vehicles,i,j,p1,p2", we have self-documenting code. Is "p1=cars[i]" really better than "pCar=mCars[iCar]"? And "p2= vehicles[**i**]" is a hard bug to spot compared to "pCar = vehicles[**iCar**]"
Jason Williams
I don't mind if you like prefixes or not - stick to what you think is best. But 29 years of programming (without prefixes, then with prefixes, then without them, then with them again) has shown me that they work fantastically well, and the programmers who use the system I've described have significantly (measurably) lower bug rates. But in the original question, I advised use of the prefixes because for a *beginner* learning pointers, prefixes give you *absolute* clarity, and thus eliminate a vast chunk of the confusion pointers entail. THis makes learning them *easier*.
Jason Williams
1) A 20 line function with 8 variables is already *much too big* for my tastes and probably violates the single responsibility principle. 2) I would be very surprised if a variable called "address" was *not* a pointer. 4) Loops express very little intent and are not idiomatic C++ (as are pointers BTW). If you want to find a match, use the `std::find_if` algorithm. But again, use whatever convention makes you and your team happy and productive. The point about beginners I agree with, it probably makes sense to make pointers explicit in names while learning them.
FredOverflow
1) You can't place arbitrary numerical limits on what is "good" code and what is "bad". Long methods are inadvisable, but so too are short ones that are complex, messy and obfuscated.2) address = "15, Ranfurly Crescent". Dang. I've seen people use names like "address" when they meant "offset", too.4) eh???. std::find - You've missed the point entirely.How about you just *try* it before you try to affirm that it isn't a good idea. Open your mind. Perhaps you won't find it useful. Perhaps you're resisting something that would make you a better programmer...
Jason Williams
P.S. 5) When you have (m)embers and (e)vents and (i)ndexes and (v)olatiles and (c)onstants prefixed by standard characters, they all get gathered together in nice little groups in the intellisense list, so auto-completing your code is faster and easier.
Jason Williams
@Jason: I still think writing loops over arrays is a very bad idea. I'm not sure I understand what you mean by "finding a match between a Vehicle and a Car", but it sounds to me like you simply want a union of two sets. [Here is an example](http://cpp.pastebin.com/NtmLmQVn) demonstrating a generic way based on existing data structures and algorithms. Note that both function templates are no longer than three lines and do exactly one thing :)
FredOverflow
@Fred: That was a simple hypothetical example that illustrates the *idea*. In any case where you wish to index several arrays, using indexer names that relate to the arrays (rather than the idiomatic "i,j,k") is clearly much better coding practice. I have given numerous examples of why "usage prefixes" work well. In 20+ years using them I have never heard a single valid argument as to why they should *not* be used. (The closest are "I don't like them", "It's more typing" and "But you can just read 2000 lines of code across 4 files to work that out, why do you need it right in front of you?")
Jason Williams
Jason is absolutely right and this is what Hungarian notation was all about, it was only the eggheads at Microsoft that made the abomination they call that way. The purpose is convey a little bit of semantic in the naming scheme so that things that do not look right can be seen directly. You have to be systematic though and you shouldn't overdo it neither like at MS, where the prefixes conveyed only the type of a variable, not semantics.
tristopia
And BTW +1 for Jason for that.
tristopia
+1  A: 

In my opinion, C++ as a language is so complex that understanding of it is still evolving. I'm still discovering new programming techniques. And C is no longer a good introduction to C++. In fact, becoming too steeped in C will teach you bad C++ habits and will tend to blind you to some of the really useful things in C++. For example, in C++, I consider pointers to be more important than in Java, but not nearly so much as in C.

There is no magic book you can read or formula you can follow to learn to think in C++. You have to practice with the concepts. Write your own programs that use them, even if they are just toys.

Here is my personal list of important C++ ideas that you should practice with and grow used to using:

  • Using swap (and in C++0x the move constructor and assignment operator) to write code with a strong exception guarantee.
  • Template metaprogramming (templates are basically a functional language inside of C++ who's output is a C++ program).
  • The RAII idiom (RAII stands for resource acquisition is initialization) - this is something in C++ that is fundamentally different from Java, and very important to understand.
  • And, related to RAII, the concept that objects of non-primitive types are routinely created without using new. You create objects directly on the stack or refer to them by inclusion rather than by reference. This is a huge, but subtle difference from Java.
  • Iterators - what the non-Javaesque use of pointers has turned into for the most part
  • And really, pointers that aren't used as iterators are just the same as variables of non-primitive types (i.e. stuff derived from Object) in Java, except for the lack of garbage collection.
Omnifarious
+3  A: 

A programming language is just a tool. The bottom line is, the more you know the better. C is a very good language to learn IMO, for the very same reasons one of the co-founders of stack overflow (Joel Spolsky) mentions in this article: http://www.joelonsoftware.com/articles/CollegeAdvice.html. I read this article before I graduated and made it a point to take his advice on learning C before I graduated.

At the end of the day, software written in any language is run on (or by) a computer chip. It's very important to understand (if you want to be a 'good' programmer anyway) what the cost is (in cpu time and programmer time) of the mechanisms you are using in whatever language you are using. High-level languages are great for programmers in some cases because they allow you to implement powerful end-user features more quickly than lower level languages such as C. However, lower-level languages in general provide better performance. The only thing you as a programmer need to consider is 'what is the right tool for the job?' You don't use a hammer to drive in a screw, blah blah insert other cooker cutter analogy here, etc.

One thing that high-level languages tend to hide from the programmer is pointers. Pointers is a very important concept to be familiar with whether you program in a language that hides them from you or not. C is a great language to learn pointers (or C++ for that matter). Recursion is another big one, but I don't think any language can really hide this concept... it's a generic problem solving concept whereas pointers is more of a mechanical detail.

Lastly, my degree did not actually require me to take a compilers course. I could have ducked it, but since it is one of the most notoriously difficult classes, I felt I would be less of a man if I didn't take it. I did horrible grade wise, but I learned so many important things in that class it was well worth the proverbial rock I tied to my GPA by taking it. If you learn how a programming language is actually implemented then you have a huge advantage vs just knowing how to work with 'language X.' Any programming language takes time to learn, even if you do have all the fundamentals in the world. Random jerks everywhere will try to tell you how easy it is to learn 'language X,' but these people are usually just insecure and want to make themselves feel good by acting like they were born with an ability to program in 'language X' when really they have just put in the hours to learn it. Nobody is born knowing this stuff, just give yourself time to learn but be smart about it. Develop a systematic method of learning a new language (my strategy always starts with writing 'hello world' in the language) and you will do fine. END RANT.

Tom
+1 for this part "Any programming language takes time to learn, even if you do have all the fundamentals in the world. Random jerks everywhere will try to tell you how easy it is to learn 'language X,' but these people are usually just insecure and want to make themselves feel good by acting like they were born with an ability to program in 'language X' when really they have just put in the hours to learn it." After reading it, I feel more confident. Thanks
Andrew-Dufresne
everybody knows one.
Tom
+2  A: 
Owen S.
A: 

If you are really thinking of mastering pointers concept , I will suggest this book:

Understanding Pointers in C by Yeshwant Kanitkar .

Its very lucid and organized book that will give you the deep insight of pointers starting from scratch to the applications of pointers.

Ashish
Kanitkar's books teach non-standard C!!
Abhinav Upadhyay
"All books by Yashwant Kanetkar including books like Let US C, Working with C, Data structure through C. The problem with his books is that, though they are easy to read, contain lots of factual errors. They do not address the fact that certain aspects of C is implementation dependent." [Link](http://www.iso-9899.info/wiki/Main_Page)
Andrew-Dufresne
A: 

If you are already working in a C++ project on a daily basis, chances are that you are already getting used to using pointers. It just takes longer time for the knowledge and recurring patterns to sink in. (If I remember correct a famous C++ guru says it takes 6 months to a year to become productive.)

A good debugger, especially one which shows the original source code and the compiled assembly code at execution time, will help you understand better.

To echo Evan http://stackoverflow.com/questions/3130104/thinking-in-c/3130118#3130118, C++ is a multi-paradigm language. To think in C++ is mainly about thinking in paradigms. For example, libtiff is entirely based on function pointers and COM is entirely about OOP using nothing but pointers, vtables and reference counting. MFC wraps a lot of things into macros and tables.

At the beginning of a project, you have a chance to choose the right paradigm. Sometimes it is limited by the project requirements especially if it needs to interface with an external environment. Once the project gets going, it will be difficult to switch. Often the choice was made for a good reason.

The only way to learn about a paradigm is to work in a project that uses it.

rwong
+1  A: 

Should I be programming in C to get "used" to this?

No, you shouldn't. C used to be a good introduction to C++ when C++ was mostly thought of as "C but with classes". C++ has evolved so much from that mindset that writing C code in C++ makes for very very bad C++ code.

What should I be doing to get used to pointers if I've never used them coming from a language such as Java?

Knowing how to use pointers in C++ implies several key areas (and you should probably learn them one after the other):

  • pointer arithmetic (adding and substracting pointers and integers, usage of zero pointer, pointers and arrays, operations with pointers); this is the part C++ shares with C.

  • pointers to functions (this part is also shared with C).

  • pointer casting (static_cast, dynamic_cast, ...). This part is C++ specific. You could also define your own cast type and experiment with that a bit (and have a look at boost::lexical_cast as an example).

  • pointers to member objects and member functions.

  • RAII for pointers and various smart pointer implementations: circularly-linked pointers, reference-counted pointers (boost::shared_ptr), unique pointers (std::auto_ptr), scoped pointers.

  • wrapping function pointers in functor classes (see std::tr1::function or boost::function).

  • object references and how they are like and unlike pointers; Where to use references and where to use pointers.

  • the similarities between pointers and iterators.

  • using operator* and operator-> to simulate pointer-like behavior for an object (and when not to abuse this).

  • pointers and constness / mutability: what is the difference between a pointer, a const pointer, a pointer to a const value and a const pointer to a const value (and when to use each), and similar using mutable pointers.

Current best practices in C++ advice against using pointers in your code unless they are managed automatically by your code (through RAII for example).

utnapistim
+1  A: 

This question has nothing to do with thinking in C++. You just need to learn more C++. It's good that you already know Java, because just about everything important in Java is directly present in (and indeed borrowed from or influenced by) C++, so you just need to learn more C++ to learn how to "map" those Java design ideas into C++ implementations.

Do not learn C to learn C++. That's a stupid myth. They are two different languages. Learn C++ to learn C++.

John