C++ Exception handlers - Page 1
Forum section: electronics / general

author: ee851
author_rank: Regular Contributor
timestamp: May 11, 2012, 10:27:04 pm
content: I am an experienced C programmer. I have dabbled with assembler programming, but nothing major. One impetus for me to learn C++ programming is its ability to throw and catch exceptions. However, would this be useful for programming of embedded systems, I wonder ? If you have used this tool in embedded programming, please share your experiences.One of the first things I have been wondering is this: Is exception handling (A) a software design technique to identify and to handle foreseen exceptions without bringing down the whole system, or (B) a debugging technique to identify and isolate some unforeseen set of events that led to the failure of a system, or (C) something else.If you have experienced another situation where exception-handling helped solve a problem, please share.

author: McMonster
author_rank: Frequent Contributor
timestamp: May 11, 2012, 11:02:10 pm
content: It's certainly the A option, safely handling forseeable events like trying to open a file that does not exist. But (assuming PC programming in this case) it's also handy for debugging, if your application fails on a kind of event that wasn't forseen they produce a stack trace and and something ranging from a generic kind of error to a detailed message regarding the event (depends on how well your code uses them) with pointing you to exact location (file and number of the line) in your code. This can lead to identifying a bug or another event you should anticipate and handle. There's also a kind of exception called an error, the difference is that they do identify a fatal condition in your application that you can't anticipate and usually can't recover from.However electronics and microcontrollers are just my hobby, so I can't tell you anything detailed about how they're used in embedded systems. I've heard that they're not used on small micros because they use a lot of memory.

author: nctnico
author_rank: Super Contributor
timestamp: May 11, 2012, 11:10:53 pm
content: I program a lot in C++ but I don't like exception handlers very much. Its like using if (error) goto handler; They are especially irritating if they occur in libraries. I prefer functions which return an error value and work from there.As with using C++ on embedded systems I'm sure it will have its benefits. Deep down below a C++ object is a struct with data members and function pointers. If you declare a new instance the functions pointers get filled and the so called constructor is called in order to initialize the data members. Unless you are going to use late binding I doubt you'll have much overhead unlike many people think. Actually, in many cases I see people emulate C++ behaviour. The Linux kernel is a very good example. If you want C++ features why not use C++ right away?But... with ever increasing complexity of projects C of C++ are getting in the way of programming. Certainly C++ has a much better string type and the STL libraries make using pointers and dynamic allocation of memory unnecessary but still I think there is room for improvement. I'd like to give eLua a try one day (seehttp://www.eluaproject.net/). Lua is a 4th generation programming language which takes a lot of the uninteresting low level stuff away.

author: amspire
author_rank: Super Contributor
timestamp: May 11, 2012, 11:13:08 pm
content: I believe exceptions are not supported for C++ programming using the g++ compiler with the Atmel AVR family. In the limited amount of embedded programming I have done, it is not something I like to do. Exceptions allow you to back out of many levels of function calls quickly, but I like avoiding too many levels of function calls anyway. Function calls can chew up the very limited RAM in embedded processors, and also chew up time, so I have often limited myself to no more then 4 levels of function calls maximum. I tend to more of a flat level State approach to programming and instead of throwing an exception, I just change to a different State.So say I have a watch dog timer for a communications process. If the watch dog timer trips indicating that the handshake has totally stalled, instead of throwing an exception, I would just change a State byte so that next time the main loop checks for the current state, it will go to a State that resets the communications. In embedded programs, I try and write all loops so the code can never get stuck in a loop. I make sure that every State function will run very quickly, even if that means to complete a task, the State function has to be run many times.There are probably better approaches, but this method works for me.Richard.

author: IanB
author_rank: Super Contributor
timestamp: May 11, 2012, 11:52:18 pm
content: As to the mechanics of exceptions in C++, they are essentially a return statement executed somewhere in the middle of a routine and returning a value of some type that you can examine later. When the exception is thrown the current level of the call stack is tidily unwound just as if a return had been executed, and control passes to the next routine up the stack. If this level does not catch and handle the exception then the exception is thrown again and the process of unwinding the call stack is repeated. It continues all the way up the call stack until main() is reached, and if that does not handle the exception it exits and returns control to the operating system. Of course in an embedded system there is no OS and it is probably a bad idea to exit from main. So exceptions are most likely not a good plan in this environment.The benefit of exceptions is that they allow you to place cause and effect in specific places where they make most sense, to avoid the need for checking the return status of every function you call, and to provide an error return path from code in object-oriented systems that doesn't have a normal return path with a status code. Essentially the main purpose of exceptions is to provide for an alternate flow of control through the code in a tidy and organized manner, so that you have a "normal path" and an "exception path". However, exceptions can be abused, they can slow your code down if misused, and they can lead to memory leaks or inconsistent states. Exceptions have a place in high level application programming, but not in low level systems programming. It is notable that C was designed as a low level systems programming language and C does not have exceptions.

author: AntiProtonBoy
author_rank: Frequent Contributor
timestamp: May 12, 2012, 12:16:06 am
content: I'm not too familiar with the tool chains used for embedded environments, but my understanding is that exception handing will make your binaries quite large, so beware.One major benefits for using C++ exceptions is that it removes the maintenance of complex if-else statements, goto statements, and gives you an opportunity to do some garbage collection when something fails. I realise goto is a natural thing for low-level C/ASM programmers, but I think it should be avoided (and made redundant) when using C++. Also note that you should not use exceptions to control the "normal" execution flow of your application. Exceptions should be regarded as a "last resort" mechanism to handle error or unforeseen situations.

author: IanB
author_rank: Super Contributor
timestamp: May 12, 2012, 12:22:08 am
content: Quote from: AntiProtonBoy on May 12, 2012, 12:16:06 amThere...fixed that for ya!

author: AntiProtonBoy
author_rank: Frequent Contributor
timestamp: May 12, 2012, 12:47:55 am
content: Hahah, well I think the following will cover your arse for most things:Code:try{}catch (const std::exception& e) {/* Trigger GC here */}catch (const std::string& e) {/* Trigger GC here */}catch (...) {/* Trigger GC here */}

author: TerminalJack505
author_rank: Super Contributor
timestamp: May 12, 2012, 05:11:40 am
content: Here are my thoughts on using C++ exception handling on microcontrollers...First, check to see that your compiler even supports them. If it doesn't then problem solved.Don't bother using them on anything less than a 32-bit MCU. They would be overkill for 8-bit MCUs. 16-bit? Hard to say, really.Decide before starting a new project whether you are going to use them or not. Don't try tacking them on to an existing project.Check to see if any of the 3rd-party libraries you are going to use uses them. If one or more do (and they can't be disabled) then that may be a good excuse to use them in your code as well. (Obviously, if a 3rd-party library is throwing exceptions then you--at the very least--need to be catching and handling them.)If you decide to use them then they will (and should) be used mostly for case A. That is, all exceptions should be expected and handled. This is the problem most people have with exception handling. They don't truly know which exceptions to expect from their code. This is made worse when using 3rd-party libraries that may be poorly documented.You frequently see code where every method of every class catchesallexceptions and simply logs them and returns an error from the method (or re-reraises the exception or throws a different exception.) This isn't exception handling! This is pretty much 'exception ignoring'. When I see this, I cringe. It tells me the developer didn't really know what exceptions to expect so he/she just punted and lumped them all into a generic handler.There are cases where this is okay. But having an exception handler for every method is just plain wrong. (C# programmers are particularly guilty of this, but I digress.)There are some exceptions that can't be caught and ignored. What if operator new() throws an exception? It's probably a bad idea to just log this and return an error. Exceptionhandlingfrequently means having to do something to (hopefully) recover from the exception. As others mentioned, resource clean-up, is sometimes necessary. (As a C++ developer learn and practice RAII so that the amount of explicit clean-up is reduced.)You will find that sometimes recovery isn't possible. These exceptions sort of fall under your case B. (Although none should be unexpected or unforeseen.) These should make their way all the way back to the point where they can best be handled and (hopefully) logged for post mortem study. If you're lucky these kinds of exceptions will only happen during development and never in the field.

author: amyk
author_rank: Super Contributor
timestamp: May 12, 2012, 09:39:32 am
content: Quote from: McMonster on May 11, 2012, 11:02:10 pmIndeed, the exception handling/unwinding mechanism is not trivial at all. A lot of extra code and data is needed to keep track of everything.Here's some of the details of how it's done on Windows PCs to give you an idea of the complexity involved:http://www.openrce.org/articles/full_view/21

author: ejeffrey
author_rank: Super Contributor
timestamp: May 12, 2012, 10:48:37 am
content: Quote from: BoredAtWork on May 12, 2012, 09:59:22 amThat doesn't make a lot of sense. The way you make sure exceptions are thrown for unexpected errors it to use exceptions for all errors. When due to a coding error or omission you fail to catch one, it propagates up to the unexpected exception handler. After all, an unexpected error is one that the calling code doesn't expect. The code that generates the exception by definition knows to expect it or it would cause a crash or silent corruption.C++, due to its C heritage, has several different methods for error handling (return codes, errno, exception handlers, directly exiting with an error message, the err() and error() family of functions, etc.). However, accepted practices is using exceptions for all out-of-the ordinary conditions, which is already the case in many more modern languages. This includes conditions like EOF, which are generally not an unexpected error, but do have to interrupt the control flow.I understand that embedded development is a different world, and that what has become standard practice in the non-embedded world may not yet be widely accepted in the embedded world. This is due to a healthy skepticism of change, desire to continue using established and well tested libraries not conforming to newer practices, and the extremely slow development of fully functional, non buggy C++ compilers for embedded targets.

author: Psi
author_rank: Super Contributor
timestamp: May 12, 2012, 01:34:40 pm
content: Yeah, unless you're coding a large project on a 32bit micro, like an ARM, C++ exception handlers are overkill.In fact i would call C++ itself overkill for 8bit micros. Normal C is all you need for 8 bit.

author: ee851
author_rank: Regular Contributor
timestamp: May 12, 2012, 01:44:43 pm
content: Thank you, gentlemen, for sharing your thoughts on this matter.TerminalJack505 and Psi, I lean toward agreeing with your advice that C++ exception-handling ought only be considered when one has the horsepower of a 32-bit CPU. Now I am wondering if it might be useful to employ C++ exception-handling as a debugging template on a 32-bit desktop computer for testing and debugging C software for an embedded system on my desktop computer. Just cut & paste C code into it for testing purposes -- C code that I will subsequently recompile for my target microcontroller. ( Depends on the availability of identical libraries for both CPUs, yes I understand. )I suppose not, if C++ exception-handling is only helpful for handling foreseen events. I can just, for example, write code likeif (b ==0) { return 1; } else { c=a/b; }to ensure my divisor is non-zero before attempting a division.I read RAII. I do not understand it. I shall make it my goal to understand it. In this context, is memory the only"resource"for an embedded application? Or does the microcontoller have other "resources"?Thus far, I have written a string benchmark program in both C and C++ to verify that the C++ version is larger (binary) but runs much faster when handling strings using its String class. But the C++ source code is much smaller and easier-to-read then the C version. However I avoided all standard string function calls in my C version, and just used char pointers for speed. This made the source code bulky, and time-consuming to debug.

author: AntiProtonBoy
author_rank: Frequent Contributor
timestamp: May 12, 2012, 03:28:05 pm
content: QuoteYou definitely don't want to use exceptions for that kind of thing. Exceptions should be only used when something drastic happened and the normal program execution can not continue within a certain scope.Quote from: ee851 on May 12, 2012, 01:44:43 pmDynamically allocated memory is a type of resource. But a resource could be any subsystem whose state must be restored before the execution flow goes out of context where the initialisation was performed. You can consider certain micro-controller I/O ports as a type of resource, which must be reset to their default state once you finished using them.Simple example: After you allocate a C++ object, some methods during the object's lifetime will allocate additional memory buffers, open ports, and so on (i.e. acquire resources). This C++ object has the sole responsibility of tracking, then de-allocating, or closing of those aforementioned resources; in other words, perform garbage collection. When that C++ object itself is destroyed, its destructor will be invoked automatically, which should contain all the necessary garbage collection code. The destructor is guaranteed to be called if it happens to reside on an unwinding stack during an exception.

author: nctnico
author_rank: Super Contributor
timestamp: May 12, 2012, 08:08:51 pm
content: Quote from: Psi on May 12, 2012, 01:34:40 pmInterestingly ARM controllers have hardware exceptions as well which catch accesses to non-existing memory, writes to read-only memory and divide by zero. In debug builds I have the handler print a stack dump. In production builds I have the handler reset the controller.

author: ee851
author_rank: Regular Contributor
timestamp: May 12, 2012, 08:28:43 pm
content: Quote from: Psi on May 12, 2012, 01:34:40 pmHardware exception? Never heard of that before.Is that another name for an externally-triggered (hardware) realtime interrupt, for which you write an ISR (interrupt service routine) that interrupts the CPU and saves its current state before branching to the first line of the ISR?

author: ee851
author_rank: Regular Contributor
timestamp: May 12, 2012, 08:34:03 pm
content: Quote from: AntiProtonBoy on May 12, 2012, 03:28:05 pm

author: IanB
author_rank: Super Contributor
timestamp: May 12, 2012, 08:41:40 pm
content: Quote from: ee851 on May 12, 2012, 08:28:43 pmYes, hardware exceptions are like interrupts.Although the name sounds similar, hardware exceptions should not be confused with software exceptions. Software exceptions are a programming construct handled by the compiler and used to control the flow of execution in a program. Software exceptions don't exist at the assembly level (unless you write code to implement that function).Hardware exceptions are like interrupts, but instead of being externally triggered by outside events they are triggered by the CPU itself when it encounters a situation that may not allow an operation to complete successfully, such as dividing by zero, or attempting to access a non-existent memory address. When this happens the CPU may either set the result to some defined error state and continue, or it may raise an exception that causes execution to branch to an exception handler provided by the user (this is configurable). The exception handler is much like an interrupt handler, in that it interrupts the normal flow of execution. The handler may attempt to fix the situation and continue where the exception occurred, or it may decide to abandon execution and restart or reset at the beginning.Sometimes an exception handler may gather information about the problem and then throw a software exception, if the software environment supports this.

author: IanB
author_rank: Super Contributor
timestamp: May 12, 2012, 09:01:12 pm
content: Quote from: ee851 on May 12, 2012, 08:34:03 pmSort of. Here's an example:Code:#include <iostream>#include <string>using namespace std;class SomeResource{private:string mName;public:SomeResource(const string &name) : mName(name) { cout << "Allocating resource " << mName << endl; }~SomeResource() { cout << "Freeing resource " << mName << endl; }};struct SomeException {};void doStuff(){// allocate our resourceSomeResource my_resource("Instance 1");// do some stuff using the resource// ...// oops, an exeption occurred, how will our resource get freed?cout << "Throwing an exception..." << endl;throw SomeException();// do more stuff// ...}int main(){try{doStuff();}catch (SomeException){cout << "...catching exception" << endl;}}And here's what the program outputs when run:Code:Allocating resource Instance 1Throwing an exception...Freeing resource Instance 1...catching exceptionAs you can see, the resource gets freed automatically so you can never have a resource leak caused by an exception.If we had tried to free the resource using some code before leaving the function the thrown exception would have bypassed that code and the resource would have leaked.

author: ejeffrey
author_rank: Super Contributor
timestamp: May 12, 2012, 09:53:47 pm
content: Quote from: ee851 on May 12, 2012, 08:34:03 pmNo. Standard C++ does not include garbage collection, and I think you are misunderstanding what garbage collection means. delete is the opposite of garbage collection. Garbage collection is a system that keeps track of all the pointers to objects, and when the last pointer goes out of scope, the object is automatically deleted, and its memory and hopefully other resources are freed. In standard C++, objects must always be deleted explicitly. Of course, when one object controls the lifetime of another, its destructor must correctly destroy those objects, but that is not the same as garbage collection.QuoteA hardware exception, also called a trap, is the way a CPU responds to an illegal operation -- whether it is division by zero or accessing an illegal memory address. They are not the same as software exceptions implemented by your language, although it is possible for the runtime environment to convert hardware exceptions to software exceptions.

author: AntiProtonBoy
author_rank: Frequent Contributor
timestamp: May 13, 2012, 01:12:38 am
content: Just to clarify: "Garbage collection" in C++ is something you have to do yourself and implement this at strategic places, such as an object's destructor. So we are talking about a concept, or a programming practice related to cleaning up resources once you finished with them. Some languages do this automatically, and thus "garbage collection" has become synonymous with the language syntax that de-allocates memory or objects. However in C++ this is not the case,newanddeleteare just as susceptible to memory leaks asmallocandfreeare.Here is one way to do (memory) garbage collection in C++:Code:class MyObject{private:int* Foo;int* Bar;public://Constructor: Use initialiser lists to default member dataMyObject() : Foo(NULL), Bar(NULL) {}//Destructor: We add garbage collection code here; destructor gets called automatically when MyObject is destroyed~MyObject(){delete[] Foo; Foo = NULL;delete[] Bar; Bar = NULL;}//Calling these methods will acquire resources during run-timevoid AllocateFoo(){if (Foo != NULL) {return;}Foo = new int;}void AllocateBar(){if (Bar != NULL) {return;}Bar = new int;}};Of course, this concept can be extended to anything else that needs initialisation and shutting down.Oh an one more thing: When you have resources allocated in objects, such as in my example above, you will also have to account for copy constructors and assignment operators to allow "deep copying" of the resources contained within them.

author: nctnico
author_rank: Super Contributor
timestamp: May 13, 2012, 01:51:53 am
content: IMHO the best way to program in C++ is trying to avoid pointers and dynamic allocation at all. There are several ways to do that. First of all the STL libraries have linked list templates like vector<> and deque<>. I use these a lot to store 'unknown' amounts of data. Secondly the C99 standard allows for sizing arrays in runtime:int old_style(int size){char *a=malloc(size);if (error) return 0;free(a);}int new_style(int size){char a;if (error) return 0;}The old style function is prone to memory leaks. The new style function uses the stack to hold the temporary data. No matter how the function is left the memory occupied by a is always freed.

author: ejeffrey
author_rank: Super Contributor
timestamp: May 13, 2012, 10:00:44 am
content: Quote from: AntiProtonBoy on May 13, 2012, 01:12:38 amNo. Garbage collection is and always has been specific to automatic memory management where the runtime environment detects when an object is no longer reachable by any valid pointers and deletes the object. Standard C++ does not include garbage collection. Please don't teach new guys incorrect terminology: it will get them in trouble down the line. What you do in C++ is just called 'memory/resource management' and you have to do it by hand with new and delete.

author: AntiProtonBoy
author_rank: Frequent Contributor
timestamp: May 13, 2012, 12:02:21 pm
content: Fair enough, I stand corrected!

author: TerminalJack505
author_rank: Super Contributor
timestamp: May 13, 2012, 03:28:24 pm
content: QuoteWikipedia has a pretty good entry onRAII. In C++, the idea is to use objects that represent the resource and have the object's constructor (usually) acquire the resource and the destructor release it. You can then rely on scope rules to ensure that the resource is released since the compiler calls an object's destructor when the object goes out of scope.RAII makes writing exception safe codemuchless tedious since you will not have to have catch blocks just to release resources.The resource doesn't have to be memory. And RAII isn't just for code where exception handling is used. Here's a class that allows for atomic blocks on AVR MCUs (which don't support exception handling, BTW)...Code://// TAtomicBlock is a simple acquistion/release wrapper class for saving SREG and disabling interrupts// upon construction and restoring the saved value of SREG upon destruction.//class TAtomicBlock{public:TAtomicBlock() { mSavedSREG = SREG; cli(); }~TAtomicBlock() { SREG = mSavedSREG; }private:uint8_t mSavedSREG;};You would use it something like this...Code:ISR(TIMER2_COMPA_vect){ // This is the ISR for the real-time clock. It runs once per second.// Display the fan's speed (in RPMs) on line 2 of the LCD module...... // Do some computations...// Don't let the rotary encoder handler use the LCD while we do...{TAtomicBlock Lock; // Disable interrupts during execution of the code in this block.... (Access the LCD...)} // <-- The 'Lock' object's dtor is called once this block is exited....}The LCD is being used in another ISR so the atomic block ensures this ISR has exclusive access to the LCD by creating a TAtomicBlock object.

author: ee851
author_rank: Regular Contributor
timestamp: May 13, 2012, 05:20:00 pm
content: What is a memory leak?I'd been thinking it means holes of unused RAM inside a thread's address space that develop as memory is allocated and deallocated during the thread's lifetime, similar to the holes that develop in the filesystems of certain operating systems (and must be defragmented). But I might be wrong.I realize this discussion is going somewhat outside the context of my original question and am okay with that.Yes, ejeffrey, you're right--I'm fuzzy on the whole idea of garbage collection."delete is the opposite of garbage collection. Garbage collection is a system that keeps track of all the pointers to objects, and when the last pointer goes out of scope, the object is automatically deleted, and its memory and hopefully other resources are freed. "So all I need to do is use new and delete statements in my code, and the linker automagically links code into the executable to invoke this "system" --based on object size --to allocate and deallocate memory as needed, eh?nctnico,Thanks for the example. I think I understand now. That's done by hidden code inserted by the C++ linker at link time, I'd imagine.So the way to have "global variables" available at all times to all objects during the lifetime of main() is to define them in the public section of objects declared prior to int main() in my source code?I share your enthusiasm for avoiding or minimizing dynamic memory allocation/deallocation, and with code in general.I am not familiar with the STL libraries, but will search for them on the web. Same with linked-list templates.Thanks, AntiProtonBoy, for that illustrative example. I understand assignment of objects toexisting objects (deep copying) requires writing a method for the equals operator and overloading it within the context of my object's definition. I hope I remember! I appreciate your taking time to write that example. I think I understand now.Thanks, IanB, for cluing me in on exception handlers. I take it they operate in a similar, architecture-dependent fashion to interrupt handlers, namely,(1) You set up the ESR to be linked to a specific physical memory address inside the thread.(2) You enable/disable the ESR by writing a specific bit pattern to a specific register in the CPU.(3) You're responsible for any "special" response to the hardware exception by putting a jump to the corresponding code into the ESR.(4) The program counter continues with the thread's next instruction when control is returned from the ESR.

author: nctnico
author_rank: Super Contributor
timestamp: May 13, 2012, 05:59:01 pm
content: Quote from: ee851 on May 13, 2012, 05:20:00 pmYou areA memory leak is allocated memory which is not freed. Memory fragmentation is another problem but there are interesting solutions for that as well. In of the microcontroller based devices I made I needed several buffers which could have changing sizes. What I wanted to avoid was memory fragmentation and using dynamic memory allocation. I ended up implementing a system which allowed to create buffers which could be expanded or shrunk based on a linked list. Each segment contained a small amount of memory and a index to the next segment (or end of buffer flag). This way I never had problems with memory fragmentation. Ofcourse this doesn't prevent an out-of-memory condition but that was not a real problem for the device.QuoteThere is an interesting book called 'C++ data structures' which also explains the underlying mechanisms of the data storage templates from the STL library:http://www.amazon.com/Plus-Data-Structures-Nell-Dale/dp/1449646751/Its a bit expensive but I got an old print from a book market for a few bucks.

author: IanB
author_rank: Super Contributor
timestamp: May 13, 2012, 06:10:03 pm
content: Quote from: ee851 on May 13, 2012, 05:20:00 pmA memory leak is simply a piece of memory that has been reserved for use by a program that never gets released when the program has finished with it and remains unused while the program runs on. Memory leaks can happen both in unmanaged memory environments like C++ and managed environments like .NET or Java. To make a memory leak all you have to do is hold on to the memory and not let it go.QuoteActually, no. It is not good to use new and delete in C++ -- in fact one could almost say "new and delete are considered harmful". I flag up the use of new and delete as suspect in code reviews.At the microcontroller level you really shouldn't be designing code that needs dynamic memory management. There's no virtual memory system and there is no huge pool of memory to start with. In a microcontroller program you want to be explicitly accounting for and controlling every resource you use by design. Your program should be completely deterministic, stable and predictable in its behaviour, able to run forever without needing a reset. It's much harder to do this when you include complex features like dynamic memory management in your program.At the desktop and server level, new and delete are very raw, low level features in C++ that are hard to use without risk of bugs or leaks. It is best to confine the use of new and delete to library code like the STL, and to have your own code use the higher level abstractions like STL containers for dynamic memory. Your code will be more readable and at the same time less prone to leaks or use of bad memory pointers. If you use C++ without the STL you are only using half of C++.

author: ee851
author_rank: Regular Contributor
timestamp: May 14, 2012, 12:49:31 am
content: Quote from: IanB on May 13, 2012, 06:10:03 pmAmen, brother.Thanks IanB, for your comments on memory leak.I have begun to educate myself on the STL, and to use its classes. No sense in reinventing the wheel.

author: TerminalJack505
author_rank: Super Contributor
timestamp: May 14, 2012, 03:15:01 am
content: Here's a little advise regarding C++. When you think you have learned the language, read Scott Meyers' bookEffective C++.This book is a classic and every serious C++ programmer has a copy. This isn't a book for learning C++ so find another book for that. It is a book that tells you all the things youneedto know to be an expert C++ developer.

author: ee851
author_rank: Regular Contributor
timestamp: May 18, 2012, 09:34:28 pm
content: Thank you for the book recommendation.