What is wrong with using goto? [duplicate] - c++

This question already has answers here:
Closed 12 years ago.
Possible Duplicates:
Why is it bad to use goto?
GOTO still considered harmful?
I was ramdomming through xkcd and saw this one (if also read some negative texts about them some years ago):
What is actually wrong with it? Why are goto's even possible in C++ then?
Why should I not use them?

Because they lead to spaghetti code.
In the past, programming languages didn't have while loops, if statements, etc., and programmers used goto to make up the logic of their programs. It lead to an unmaintainable mess.
That's why the CS gods created methods, conditionals and loops. Structured programming was a revolution at the time.
gotos are appropriate in a few places, such as for jumping out of nested loops.

Nothing is wrong with goto if it is used properly. The reason it is "taboo" is because in the early days of C, programmers (often coming from an assembly background) would use goto to create incredibly hard-to-understand code.
Most of the time, you can live without goto and be fine. There are a few instances, however, where goto can be useful. The prime example is a case like:
for (i = 0; i < 1000; i++) {
for (j = 0; j < 1000; j++) {
for (k = 0; k < 1000; k++) {
...
if (condition)
goto break_out;
....
}
}
}
break_out:
Using a goto to jump out of a deeply-nested loop can often be cleaner than using a condition variable and checking it on every level.
Using goto to implement subroutines is the main way it is abused. This creates so-called "spaghetti code" that is unnecessarily difficult to read and maintain.

There is nothing wrong with goto in itself. It's a very useful construct in programming and has many valid uses. The best that comes to mind is structured resource freeing in C programs.
Where goto's go wrong is when they are abused. Abuse of gotos can lead to thoroughly unreadable and unmaintainable code.

In 1968, Edsger Dijkstra wrote a famous letter to the editor of Communications of the ACM GOTO is considered harmful in which he laid out the case for structured programming with while loops and if...then...else conditionals. When GOTO is used to substitute for these control structures, the result is very often spaghetti code. Pretty much every programming language in use to day is a structured programming language, and use of GOTOs has been pretty much eliminated. In fact, Java, Scala, Ruby, and Python don't have a goto command at all.
C, C++ and Perl still do have a GOTO command, and there are situations (in C particularly) where a GOTO is useful, for example a break statement that exits multiple loops, or as a way of concentrating cleanup code in a single place in a function even when there are multiple ways to terminate the function (e.g. by returning error codes at multiple points in the progress of a function). But generally its use should be restricted to specific design patterns that call for it in a controlled and recognized way.
(In C++, it's better to use RAII or a ScopeGuard (more) instead of using GOTO for cleanup. But GOTO is a frequently used idiom in the Linux kernel (another source) which is a great example of idiomatic C code.)
The XKCD comic is a joke on the question "Should GOTO always be considered harmful when there are certain specific design patterns that are helped greatly by its use?"

Did you google the issue?
The founder of the anti-goto movement is Edsger Dijskstra with his legendary "Goto Considered Harmful"
To get you started you can goto (ha ha!) http://en.wikipedia.org/wiki/GOTO

It's possible in C++ because it's possible in C. Whether you should or shouldn't use it is long-standing religious war.
It was a design goal of C++ that 99-point-something percent of C programs in the wild should compile and run with the same functionality in C++. Including goto was part of the effort to reach that goal.

Related

What to use instead of Goto Statements? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I'm wondering what I should be using instead of goto statements?
Should I be using nested if/while/do-while statements?
They say that using goto creates 'spaghetti code', but surely if someone is writing a large console application and they have if statement after if statement in an attempt to control the flow, that's going to make a mess?
I'm asking as many people have asked why the goto statement is bad, but not what to replace it with. I'm sure a lot of beginners could do with this.
This is for C++.
You are much better off using functions, loops, and conditional statements. Use break and continue as necessary.
I can nearly guarantee you any situation in which you are utilizing goto there is a better alternative. There is one notable exception to this: multi-level break.
while(1){
while(1){
goto breakOut;
}
//more code here?
}
breakOut:
In this one (relatively) rare situation, goto can be used in place of a typical "break" to make it clear we are actually getting out of a nested loop. The other way to approach this is with a "done" variable:
while(!done){
while(!done){
done = true;
break;
}
if(done){break;}
//More code here? If so, the above line is important!
}
As you can see, the done variable is more verbose when you have additional processing in outer loops, so a goto is a cleaner way of breaking free!
However, in 99% of cases you really, really, don't want to start writing a bunch of goto statements. Really think through each one.
With functions the above could also be written like so:
bool innerLoop(){
while(1){
return false;
}
return true;
}
...
while(innerLoop()){ //can only be written this way if the inner loop is the first thing that should run.
//More code here?
}
...
Sometimes breaking an inner loop out in this way can be messy if there are a lot of dependencies on the outer one. But it remains a viable way of breaking out of code early with return statements instead of goto or break.
If you can write your logic using a clean, modern construct, then use it. Otherwise, if goto makes sense, use it.
In general, goto can make your code harder to read and follow the flow of the code. For that reason, newbies are told to avoid goto altogether. This encourages them to think in terms of other constructs.
But some people just get religious about it. Coding is not a religion. And if a goto makes sense, C++ has a perfectly valid goto statement and you should use it when it makes good sense.
It doesn't make sense to me to ask what you should use instead of goto. You can generally use some type of loop or other construct, depending on what you are doing. But where goto makes sense, use it.
Don’t listen to people who say "never use goto". You're quite right that there are cases where nesting scoped blocks will make a heck of a lot more mess than a goto. It has its place, just as a switch/case does. However, with functions you can often refactor away the entire argument and keep people happy.
Simply forget that there is the goto statement in C++ and there will not be questions about how to replace the goto.:)
As for me I never see a code with goto statement that I could call it as a good code. Usually a goto statement is the source of some kind of errors and difficulties. Especially it is difficult to modify such code. Moreover one goto statement usually starts to produce other goto statements in the code.:)
The goto is bad because it allows you to jump from context to context. The context is a vector of all your variables (with their values) at a particular point of your program. A program execution graph shows you how your program jumps from context to context. It's in your best interests to keep the execution graph as simple as possible. The simplest one is a chain, the next step is an execution tree. A loop adds complexity, but it's a managed complexity. If you have a node in your execution graph, which is reachable via more than one execution path, and you need to understand a context at this node, then you'll need to follow more than one execution path back. These "merge" nodes add a lot to the complexity of your program. Each labeled statement (the goto target) is a potential merge node.
So, try don't use the goto operator at all - the language itself will force you to find a manageable solution using loops, boolean variables, classes, functions etc. and your program will be more clear and understandable. C++ exceptions is another manageable way to jump between contexts.
There are computing geniuses, who can keep in their minds and process very complex execution graphs, so they don't care much about complexity of their programs or a next programmer, who will be assigned to support or take over their code in the future. I guess, we have some of them here :-)

Why and when should a goto be used in C / C++? [duplicate]

This question already has answers here:
Examples of good gotos in C or C++ [closed]
(16 answers)
Closed 9 years ago.
I know lots of questions about why not use goto, why goto is bad practice, why goto was create by devil, why the fingers of those who type goto should be ripped off, etc...
And in many answers to this questions , this question, and even at wikipedia it's possible to find reasons pro / against goto.
Even Stackoverflow has a goto tag :)
But, obviously, goto is accepted as a valid command, otherwise your compiler / interpreter wouldn't know what to do with it. Even in C / C++ it's possible to use goto, and that language even has a formal, ISO specification.
So, probably, there should be some case where only by using goto it's possible to accomplish some task. Then, why and when should a goto be used in C / C++ ?
Edit:
Just to make sure:
1 - this question doesn't require debate. It should be answerable: giving one or more cases where goto is the only solution, or stating no, it's always possible to avoid a goto. Of course, I'm not the only who can decide whether it should be closed or not, but I don't think that "too broad, asks for debate, etc" are reasons to close it.
2 - There might be some cases where goto make the code cleaner, faster, etc. I don't want those. I want to know if there exists one case where goto is the only solution (no, it's not a dup of that "give good examples of goto" question)
3 - I'll accept any downvote, with a smile on my face, if the downvote is justified. But I'm pretty sure that this question has an answer and has done previous research about the subject. Downvoting simple because those 4-letters taboo word that starts with a "G" was used... sorry...
There is no circumstance under which a goto is strictly necessary: you can always avoid it if you really want to, but to do that for purely idealogical reasons is a mistake.
For example, a friend of mine wrote a wavelet transform function that had (something like) 15 nested loops. In the event of an error in those loops, he had a goto to a cleanup block just before the function's return statement. To achieve the same effect without a goto would have involved setting a flag and testing it at every loop level, which would have made his code far less readable. In these circumstances, goto was the right choice.
The latest MISRA standard now allows gotos.
A good example where gotos make sense is when you have a large routine with a lot of exits points. You can have many return statements (not good) convolute the code with 'structured programming' conditionals (also not good) or a "goto Done; which sends the program to a set of ending statements before returning.
The MISRA standard basically allows gotos for these sort of circumstances. I think 'only downward' is one of their criteria.
The only reason I use a goto is when it is for an error return condition from a function that needs some common cleanup. The target of the goto is near the end of the function and the "normal" return returns before the label.
Here is an example where only goto will work:
https://stackoverflow.com/a/245801/193848
Basically if you have multiple nested for loops, the only way to break out of all the loops from an inner loop is with a goto statement (since unlike some other languages the C break keyword doesn't support a parameter for the number of nesting levels to break out).

Jumping to a specific line in code using C

Sorry if this question is silly, but I can't seem to find the answer on Google. I haven't done C programing in a while and for the life of me remember how, in C or C++, to jump back (or forward) to a specific line in code. If I remember right, there was a way to do this.
Thanks for the help!
Cheers!
The infamous goto, in conjuntion with labels.
label_name:
goto label_name;
Before using it, search for 'goto considered harmful'.
C and C++ do not have a concept of 'lines' after the preprocessing stage. As such, you cannot 'jump' to a line of code.
If you want to jump to a line of code in your editor, this depends on what editor you are using. If you want to jump to a specific statement (not line) at runtime, you could use goto, but this should be avoided for most circumstances, as it leads to difficult to understand code, and other control-flow structures are more appropriate in most cases.
If you want the nasty and easy solution: goto and then a label which indicates the line of code you want to go to.
Normally though, you'd have a function with the specific functionality you want to invoke, and call that function.
Use a goto statement, like this:
goto SomeLine;
// Code code code...
SomeLine:
Note that this is considered extremely bad practice. Chances are, there's a better way to organize your code that avoids the need altogether.
I do also think that the goto instruction should not be used when you can help it.
However, contrary to many other languages, there isn't a neat way to exit from multi-layered if() blocks and the easiest is to the goto in this case.
What I suggest is that you add comments and use wisely named labels (l1: ... goto l1; sucks.)
Note that people will tell you that the goto is bad, and use the break and continue statements in loops like crazy. They have the exact same side effect as the goto instruction and could be considered as bad (but aren't).
There are some options to do it: 'goto' instruction, setjmp/longjmp functions. Also you can use in c++ SEH (exception propagation and handling), but it isn't simple. And if you really nead such thing as jumping to particular line of code, I will recommend you to rewrite your code using loops and conditionals with additional state variables. Because you have serious problem with structure or design of your code. It may look ugly but it is more safer than using goto and other "black magic"

Is C still being widely used in game engines? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
The title is a bit of a misnomer, what I mean really is "C with classes".
Let me explain, recently I bought the book ShaderX7 which came with a lite (and old) copy of the Unigine engine for one of the articles about shadow mapping techniques.
I was dabbling through the code when I realized that, while the author was using C++ and inheritance and all the C++ goodness, most if not all the method content was essentially C-style code; for example:
int Shader::get_param(const char *name,char *src,String &dest) const {
char *s = src;
int size = (int)strlen(name);
while(*s) {
if(!strncmp(s,name,size)) {
if((s == src || strchr("\n\r",*(s - 1))) && strchr(" \t",*(s + size))) {
src = s;
s += size;
dest.clear();
while(*s && strchr(" \t",*s)) s++;
while(*s && strchr(" \t\n\r",*s) == NULL) dest += *s++;
if(dest.isEmpty()) {
Log::error("Shader::get_param(): can't get \"%s\" \n",name);
return 0;
}
memmove(src,s,strlen(s) + 1);
return 1;
}
}
s++;
}
return 0;
}
I am not saying this is bad, it does the job and that's what matters but I'm more used to C++ style constructs, with std::string, vectors etc... and I make big use of the Boost libraries; so this kind of style come as a bit of a surprise to me.
Is it really better/faster to use this kind of code than to go the generic, OO way ?
Did I fall into the "too much abstraction" trap ?
Edit: corrected method name to make it clear what it is doing.
First and foremost I must admit that I'm not a games developer, even though I have developed a fully functional 3D game engine in the past.
That aside, I do have a few words about optimizations, "spoiling" languages and so on.
When developing an application — any application — the golden rule of optimizations is "don't optimize before you make it work." You need to fully support all the functionality you want in your application, and only then you should optimize it. The reasons vary; the most important one is that while you may believe something is "slow," it may not be your bottleneck. You may be spending a lot of time optimizing something that doesn't require optimization. Furthermore, optimizations often blur your code simplicity and maintainability, which may lead to bugs in the near or far future. If this piece of code didn't require optimizations, you've complicated the code for nothing.
While that is the golden rule of optimizations, there is one big exception. When you know in advance that your application will be stressed out to the max, you need to make some different choices in the beginning (in the architecture or in the design phases) and also along the way. Also, the general rule that the platforms are getting better and faster doesn't apply for games, where the competition between the developers is on the very edge of technology. Here are several points to consider:
Some lingual features may be costly. Exceptions in C++ are a good example.
Some lingual features may actually save you code and will cost little or nothing during runtime. C++ templates are a good example, though you still may wind up creating lots of code during compilation, leading to a bigger binary, and therefore lower performance, potentially.
Infrastructures (STL for example) are generic. By making a solution specific to your domain, you MAY be improving your performance. A simple example — if you have a vector that will always be 3 items long, you will definitely be better than the stl::vector implementation. However, this is not always the case. For further reading, see chapter 11 of "Efficient C++" by Dov Bulka. This is an excellent book in general for your question.
In general, using C with classes is a good start for writing fast code while retaining a structured and well-designed project, but one should not neglect the whole of C++ excellent features. More often than not, trying to roll out your own solution to a problem covered by C++ (e.g., polymorphism) will be slower than the out-of-the-box solution, unless you can make the solution VERY specific to the problem at hand.
C++ without STL
As I have seen it in my professional history, what is mostly used in game development is not C with classes, but rather C++ without STL. Some parts of STL are considered too slow for a reasonable game engine performance, most notably the streams. Other parts provide reasonable general performance, but the way memory allocation is handled is mostly unacceptable for games - this applies to string and vector libraries in most scenarios. Excellent extensive discussion of this can be found in EASTL white paper. Game developers frequently use boost or even implement their own alternative to part of whole of STL (see Game STL or EASTL).
No exceptions
There is one particular language feature which is never used in any performance critical engine parts - the exception handling. This is because on the most important game development platform (Visual Studio x86/x64) the exceptions are quite costly, and you pay some cost even when no exceptions are hit. The exceptions are avoided into the extent some development console platforms even do not provide them, or the support is known to be incomplete, unreliable and basically "broken".
Used to C
Other than that, it often happens that game programmers use C instead of C++ simply because they are used to it.
If you really want to be drawing graphics as fast as possible, and you start off by saying
int size = (int)strlen(name);
that looks like barking up the wrong tree.
What does get_something get? It doesn't appear to be graphical.
Optimization doesn't consist of doing the wrong thing very quickly. It's about cutting the fat and spending all the time on the important stuff. If your graphics engine wastes a significant number of cycles on string processing, it has an issue that changing languages probably won't solve.
So… write auxiliary functions as expediently, maintainably, and clearly as possible. When you need to micro-optimize the critical path, C++ still covers the low-level style.
If it:
Works and you're happy with it, don't touch it.
Doesn't work, change it the way you like, as long as it's fixed afterwards.
Works and it's not fast enough, make it faster (NOT without profiling first).
I'll guess that you're falling into case 1, so I'd advise to leave it alone. If you need to change things, and don't have serious performance concerns, by all means dish out some C++isms on it. In the general case I find it difficult to read C-style C++ programmers, they either:
Haven't had time or don't care to learn the C++ way to do things (which really isn't acceptable from a safety perspective),
are cherry-picking the parts of C++ they actually need (very wise),
or they honestly need the performance characteristics of C (very rare).
Looking at the code it could be any of these cases. Either way it doesn't matter now, the code is in your hands.

Guidelines to improve your code

Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
What guidelines do you follow to improve the general quality of your code? Many people have rules about how to write C++ code that (supposedly) make it harder to make mistakes. I've seen people insist that every if statement is followed by a brace block ({...}).
I'm interested in what guidelines other people follow, and the reasons behind them. I'm also interested in guidelines that you think are rubbish, but are commonly held. Can anyone suggest a few?
To get the ball rolling, I'll mention a few to start with:
Always use braces after every if / else statement (mentioned above). The rationale behind this is that it's not always easy to tell if a single statement is actually one statement, or a preprocessor macro that expands to more than one statement, so this code would break:
// top of file:
#define statement doSomething(); doSomethingElse
// in implementation:
if (somecondition)
doSomething();
but if you use braces then it will work as expected.
Use preprocessor macros for conditional compilation ONLY. preprocessor macros can cause all sorts of hell, since they don't allow C++ scoping rules. I've run aground many times due to preprocessor macros with common names in header files. If you're not careful you can cause all sorts of havoc!
Now over to you.
A few of my personal favorites:
Strive to write code that is const correct. You will enlist the compiler to help weed out easy to fix but sometimes painful bugs. Your code will also tell a story of what you had in mind at the time you wrote it -- valuable for newcomers or maintainers once you're gone.
Get out of the memory management business. Learn to use smart pointers: std::auto_ptr, std::tr1::shared_ptr (or boost::shared_ptr) and boost::scoped_ptr. Learn the differences between them and when to use one vs. another.
You're probably going to be using the Standard Template Library. Read the Josuttis book. Don't just stop after the first few chapters on containers thinking that you know the STL. Push through to the good stuff: algorithms and function objects.
Delete unnecessary code.
That is all.
Use and enforce a common coding style and guidelines. Rationale: Every developer on the team or in the firm is able to read the code without distractions that may occur due to different brace styles or similar.
Regularly do a full rebuild of your entire source base (i.e. do daily builds or builds after each checkin) and report any errors! Rationale: The source is almost always in a usable state, and problems are detected shortly after they are "implemented", where problem solving is cheap.
Turn on all the warnings you can stand in your compiler (gcc: -Wall is a good start but doesn't include everything so check the docs), and make them errors so you have to fix them (gcc: -Werror).
Google's style guide, mentioned in one of these answers, is pretty solid. There's some pointless stuff in it, but it's more good than bad.
Sutter and Alexandrescu wrote a decent book on this subject, called C++ Coding Standards.
Here's some general tips from lil' ole me:
Your indentation and bracketing style are both wrong. So are everyone else's. So follow the project's standards for this. Swallow your pride and setup your editor so that everything is as consistent as possible with the rest of the codebase. It's really really annoying having to read code that's indented inconsistently. That said, bracketing and indenting have nothing whatsoever to do with "improving your code." It's more about improving your ability to work with others.
Comment well. This is extremely subjective, but in general it's always good to write comments about why code works the way it does, rather than explaining what it does. Of course for complex code it's also good for programmers who may not be familiar with the algorithm or code to have an idea of what it's doing as well. Links to descriptions of the algorithms employed are very welcome.
Express logic in as straightforward a manner as possible. Ironically suggestions like "put constants on the left side of comparisons" have gone wrong here, I think. They're very popular, but for English speakers, they often break the logical flow of the program to those reading. If you can't trust yourself (or your compiler) to write equality compares correctly, then by all means use tricks like this. But you're sacrificing clarity when you do it. Also falling under this category are things like ... "Does my logic have 3 levels of indentation? Could it be simpler?" and rolling similar code into functions. Maybe even splitting up functions. It takes experience to write code that elegantly expresses the underlying logic, but it's worth working at it.
Those were pretty general. For specific tips I can't do a much better job than Sutter and Alexandrescu.
In if statements put the constant on the left i.e.
if( 12 == var )
not
if( var == 12 )
Beacause if you miss typing a '=' then it becomes assignment. In the top version the compiler says this isn't possible, in the latter it runs and the if is always true.
I use braces for if's whenever they are not on the same line.
if( a == b ) something();
if( b == d )
{
bigLongStringOfStuffThatWontFitOnASingleLineNeatly();
}
Open and close braces always get their own lines. But that is of course personal convention.
Only comment when it's only necessary to explain what the code is doing, where reading the code couldn't tell you the same.
Don't comment out code that you aren't using any more. If you want to recover old code, use your source control system. Commenting out code just makes things look messy, and makes your comments that actually are important fade into the background mess of commented code.
Use consistent formatting.
When working on legacy code employ the existing style of formatting, esp. brace style.
Get a copy of Scott Meyer's book Effective C++
Get a copy of Steve MConnell's book Code Complete.
There is also a nice C++ Style Guide used internally by Google, which includes most of the rules mentioned here.
Start to write a lot of comments -- but use that as an opportunity to refactor the code so that it's self explanatory.
ie:
for(int i=0; i<=arr.length; i++) {
arr[i].conf() //confirm that every username doesn't contain invalid characters
}
Should've been something more like
for(int i=0; i<=activeusers.length; i++) {
activeusers[i].UsernameStripInvalidChars()
}
Use tabs for indentations, but align data with spaces
This means people can decide how much to indent by changing the tab size, but also that things stay aligned (eg you might want all the '=' in a vertical line when assign values to a struct)
Allways use constants or inline functions instead of macros where posible
Never use 'using' in header files, because everything that includes that heafer will also be affected, even if the person includeing your header doesn't want all of std (for example) in their global namespace.
If something is longer than about 80 columes, break it up into multiple lines eg
if(SomeVeryLongVaribleName != LongFunction(AnotherVarible, AString) &&
BigVaribleIsValid(SomeVeryLongVaribleName))
{
DoSomething();
}
Only overload operators to make them do what the user expects, eg overloading the + and - operators for a 2dVector is fine
Always comment your code, even if its just to say what the next block is doing (eg "delete all textures that are not needed for this level"). Someone may need to work with it later, posibly after you have left and they don't want to find 1000's of lines of code with no comments to indicate whats doing what.
setup coding convention and make everyone involved follow the convention (you wouldn't want reading code that require you to figure out where is the next statement/expression because it is not indented properly)
constantly refactoring your code (get a copy of Refactoring, by Martin Fowler, pros and cons are detailed in the book)
write loosely coupled code (avoid writing comment by writing self-explanatory code, loosely coupled code tends to be easier to manage/adapt to change)
if possible, unit test your code (or if you are macho enough, TDD.)
release early, release often
avoid premature optimization (profiling helps in optimizing)
In a similar vein you might find some useful suggestions here: How do you make wrong code look wrong? What patterns do you use to avoid semantic errors?
Where you can, use pre-increment instead of post-increment.
I use PC-Lint on my C++ projects and especially like how it references existing publications such as the MISRA guidelines or Scott Meyers' "Effective C++" and "More Effective C++". Even if you are planning on writing very detailed justifications for each rule your static analysis tool checks, it is a good idea to point to established publications that your user trusts.
Here is the most important piece of advice I was given by a C++ guru, and it helped me in a few critical occasions to find bugs in my code:
Use const methods when a method is not supposed to modify the object.
Use const references and pointers in parameters when the object is not supposed to modify the object.
With these 2 rules, the compiler will tell you for free where in your code the logic is flawed!
Also, for some good techniques you might follow Google's blog "Testing on the Toilet".
Look at it six months later
make sure you indent properly
Hmm - I probably should have been a bit more specific.
I'm not so much looking for advice for myself - I'm writing a static code analysis tool (the current commercial offerings just aren't good enough for what I want), and I'm looking for ideas for plugins to highlight possible errors in the code.
Several people have mentioned things like const correctness and using smart pointers - that's the kind of think I can check for. Checking for indentation and commenting is a bit harder to do (from a programming point of view anyway).
Smart pointers have a nice way of indicating ownership very clearly. If you're a class or a function:
if you get a raw pointer, you don't own anything. You're allowed to use the pointee, courtesy of your caller, who guarantees that the pointee will stay alive longer than you.
if you get a weak_ptr, you don't own the pointee, and on top of that the pointee can disappear at any time.
if you get a shared_ptr, you own the object along with others, so you don't need to worry. Less stress, but also less control.
if you get an auto_ptr, you are the sole owner of the object. It's yours, you're the king. You have the power to destroy that object, or give it to someone else (thereby losing ownership).
I find the case for auto_ptr particularly strong: in a design, if I see an auto_ptr, I immediately know that that object is going to "wander" from one part of the system to the other.
This is at least the logic I use on my pet project. I'm not sure how many variations there can be on the topic, but until now this ruleset has served me well.