[Dev-C++] Deliberate crashes - more information
Open Source C & C++ IDE for Windows
Brought to you by:
claplace
|
From: Bob W. <bo...@ph...> - 2002-04-08 21:44:13
|
Ladies and gentlemen: Earlier I posted an lengthy "treatise" on problems related to quote from = Sams Teach Yourself C++ in 24 Hours, third Edition by Jesse Liberty. = Since that posting I have exchanged several lengthy emails with the = author concerning what I perceived as a problem with the wording of his = warning. During the corse of the day, I believe we have come to an = understanding. Mr. Liberty has asked that I inform the readers of the = Dev-C++ User Mailing List of the results of this discussion. He was = concerned that my comments would make people think that he had "got this = wrong." To that end, I am forwarding the entire thread of our = correspondance in reverse cronological order.=20 -------------------------------------------------------------------------= ------- -------------------------------------------------------------------------= ------- No problem. -------------------------------------------------------------------------= ------- -------------------------------------------------------------------------= ------- Okay, I'll work on it. Thanks for the feedback! -j ------------------------------- Jesse Liberty Liberty Associates, Inc. .NET Training & Development http://www.LibertyAssociates.com=20 -------------------------------------------------------------------------= ------- -------------------------------------------------------------------------= ------- Jesse, I don't think this substantially changes the meaning of the chapter, = but you are of course free to disagree. Neither do I, but I would suggest that: Calling delete on that pointer again may crash your program! is neither as strong a warning nor as precise as what I suggested. By = simply inserting "may," you might be weakening the warning to the point = that the uninitiated (or, if you prefer, the great unwashed masses = uncleansed by the purity of C++) would not consider it grevious error to = not set used pointers to null.=20 Regards, Bob -------------------------------------------------------------------------= ------- -------------------------------------------------------------------------= ------- Bob, Yes, of course, the book should have made the sentence more precise, and = I'll fix that. The example you quoted in your original post, however, = was not on point: it showed the reuse of a deleted pointer, and that of = course will crash. I thought at the time you were complaining that = marking the pointer to null did not protect you from that crash (which I = never said it would). It turns out, apparently that you were actually = complaining that the non-nulled deleted pointer did not crash as I said = it would >> How could someone who is expert enough to write a beginning book on = C++ make such an error=20 Seems like a bit of overstatement to me, but I will in the next edition = qualify the sentence to=20 Calling delete on that pointer again may crash your program! I don't think this substantially changes the meaning of the chapter, but = you are of course free to disagree. Thanks. -j ------------------------------- Jesse Liberty Liberty Associates, Inc. .NET Training & Development http://www.LibertyAssociates.com=20 -------------------------------------------------------------------------= ------- -------------------------------------------------------------------------= ------- Jesse, Yes. It will crash the program. Sooner or later. If you call delete on = a pointer and you do not set it to null, it is pointing to random = memory. That may work for a while, but it certainly will crash sooner or = later. The only safe alternative is declare it null. =20 A simple declarative sentence that purports to state a universal fact = without any clauses that restrict or modify the universality of that = fact must be assumed to apply to all situations. In making a simple = declarative statement without any sort of limiting modifiers, you state = that all programs will crash. They do not. Your quote appears on page = 147. Directly below the quote is an example program which will not crash = if you delete a deleted pointer. In the simplest employment of = Aristotelian logic, if you show that something contradicts itself, you = have shown that the thing is untrue. I have done that, therefore your = statement is incorrect, invalid, or not true. Like it or not, you made = an error when you wrote the warning. Using an exclamation point to end = the sentence under discussion only strengthens my criticism.=20 That said, I concur that a dangling pointer is like a smoldering ember = in a room full of gasoline and gunpowder. Further I agree that only a = fool or a very inexperienced or careless programmer fails to both return = memory to the heap and set pointers to null after they have been used.=20 You have a few things confused here: 1. Delete a pointer and do not null it. Then call delete again. It CAN = crash immediately, and will crash sooner or later. I go back to what I said before. Your quote from the book is a absolute. = It is not a conditional statement as "It CAN crash immediately" above = is. Simply put, the book should have had been more accurate. Your entire = sentence above, "It CAN crash immediately, and will crash sooner or = later", suffers from the same problem. You and I can both write a simple = program that deletes a deleted pointer and the program will not crash = but run through to its normal termination. Such a contradiction makes = the sentence above and in the book inaccurate. The boxed warning on page = 147, should have read:=20 When you call delete on a pointer, the memory it points to is freed. = Calling delete on that pointer again may not cause a program to crash = immediately, and a simple program like the one in listing 9.4 below may = not crash at all, but more complex, longer running programs will = ultimately crash.=20 If your warning had been worded in that fashion, it would have been 100% = accurate, and we would not be having this discussion. 2. Delete a pointer and use it again (e.g., assign a value to it). = That will crash, sooner or later Agreed , but the criticism and comments discussed above apply to this = absolute statement as well.=20 3. Delete a pointer and assign null. Then delete again. That is safe, = as I said in the book Agreed.=20 4. Delete a pointer and assign null and then reuse it. Should crash = right away Agreed.=20 Your example in your email was of #4, and it crashes just as it said. = The book was not wrong. I'm sorry I wasn't clearer, but the book was = correct. This may be a very nit-picky argument that deals with both the syntax = and grammar of English, but your warning in the book is wrong. Examine = the original statement on page 147, what you have posted to me, and what = I have posted above. Hopefully such an examination will show you why I = am so adamant. If you cannot see the difference, and why I maintain that = the warning in the book is wrong, I will try to give you a better = explanation of why that is so.=20 Please post a correction to the dev-c mailing list you originally = posted the criticism on. I will be happy to oblige once the issue is settled.=20 -------------------------------------------------------------------------= ------- -------------------------------------------------------------------------= ------- Bob, I am sorry as well. What you said, and I quote, "When you call delete on = a pointer, the memory it points to is freed. Calling delete on that = pointer again will crash your program!" In point of fact it does not = crash the program. Try it with either the Bloodshed or the VC++ 6.0 = compiler and you will see what I mean. =20 Yes. It will crash the program. Sooner or later. If you call delete on a = pointer and you do not set it to null, it is pointing to random memory. = That may work for a while, but it certainly will crash sooner or later. = The only safe alternative is declare it null. =20 You have a few things confused here: 1. Delete a pointer and do not null it. Then call delete again. It CAN = crash immediately, and will crash sooner or later. 2. Delete a pointer and use it again (e.g., assign a value to it). That = will crash, sooner or later 3. Delete a pointer and assign null. Then delete again. That is safe, as = I said in the book 4. Delete a pointer and assign null and then reuse it. Should crash = right away Your example in your email was of #4, and it crashes just as it said. = The book was not wrong. I'm sorry I wasn't clearer, but the book was = correct. PS: Please do update the mailing list (I don't have the email = address) on which you posted this msg; I'd hate for folks to think I got = this wrong. Please excuse my ignorance, but update what mailing list? Or perhaps = you mean to post a correction. =20 Please post a correction to the dev-c mailing list you originally = posted the criticism on. -------------------------------------------------------------------------= ------- -------------------------------------------------------------------------= ------- I'm sorry but the book is correct. Please examine what I wrote and = compare it to what you did in your test program. I said you can set a pointer to null and then delete it without it = crashing. That is 100% correct. Calling delete on a null pointer is guaranteed to be safe. I am sorry as well. What you said, and I quote, "When you call delete on = a pointer, the memory it points to is freed. Calling delete on that = pointer again will crash your program!" In point of fact it does not = crash the program. Try it with either the Bloodshed or the VC++ 6.0 = compiler and you will see what I mean.=20 I did not say you can then try to use the pointer, or assign a new = value to it. You can not, and I make that explicitly clear in the book.=20 You write: If set pHeap to null, however, and then try to assign *pHeap a value, = as shown below, the program will crash.=20 Right. It will crash, as it should; once set to null you can not then = assign a value to it. All you can safely do is call delete.=20 I agree wholeheartedly, it should crash and it does. However, that was = not my initial criticism. It was an outgrowth of experimentation to see = if the program would crash as similar programs in other languages do if = you try to manipulate a null pointer.=20 As part of my ongoing effort to support my books, I now offer a FAQ, = source code and related materials on my web site: = http://www.LibertyAssociates.com. While you are there, you may want to = sign up for my on-line support discussion center: = http://forums.delphiforums.com/LibertyBooks. I'm happy to discuss this = in detail on the discussion center if there is still any confusion. I will certainly log on to your forms. Thanks for the link.=20 PS: Please do update the mailing list (I don't have the email address) = on which you posted this msg; I'd hate for folks to think I got this = wrong. Please excuse my ignorance, but update what mailing list? Or perhaps you = mean to post a correction.=20 -------------------------------------------------------------------------= ------- -------------------------------------------------------------------------= ------- I'm sorry but the book is correct. Please examine what I wrote and = compare it to what you did in your test program. I said you can set a pointer to null and then delete it without it = crashing. That is 100% correct. Calling delete on a null pointer is guaranteed to be safe. I did not say you can then try to use the pointer, or assign a new value = to it. You can not, and I make that explicitly clear in the book.=20 You write: If set pHeap to null, however, and then try to assign *pHeap a value, as = shown below, the program will crash.=20 Right. It will crash, as it should; once set to null you can not then = assign a value to it. All you can safely do is call delete.=20 In fact elsewhere in the book I point out that this is a feature, it = crashes reliably, as opposed to what happens if you delete memory and do = not assign it to null (in which case, if you use the pointer you = overwrite random memory and it crashes unpredictably). As part of my ongoing effort to support my books, I now offer a FAQ, = source code and related materials on my web site: = http://www.LibertyAssociates.com. While you are there, you may want to = sign up for my on-line support discussion center: = http://forums.delphiforums.com/LibertyBooks. I'm happy to discuss this = in detail on the discussion center if there is still any confusion. Thank you.=20 -j PS: Please do update the mailing list (I don't have the email address) = on which you posted this msg; I'd hate for folks to think I got this = wrong. ------------------------------- Jesse Liberty Liberty Associates, Inc. .NET Training & Development http://www.LibertyAssociates.com=20 -------------------------------------------------------------------------= ------- -------------------------------------------------------------------------= ------- (I forwarded my original message to Mr. Liberty at = jli...@li...) I will appologize in advance for the length of this message. Anyone who = has much experience in programming knows pointers are an extremely = powerful and useful construct, but that they can be the quickest path to = the hellfire and damnation of runtime erros and program crashes if = careful attention is not paid to how they are used.=20 With that as a backdrop here is a quote from Sams Teach Yourself C++ in = 24 Hours, third Edition by Jesse Liberty.=20 -------------------------------------------------------------------------= ------- When you call a delete on a pointer, the memory it points to is freed. = Calling delete on that pointer again will crash your program! When you = delete a pointer, set it to 0 (null). Calling delete on a null pointer = is guaranteed to be safe. For example Animal: *pDog =3D new Animal; delete pDog; // frees the memory pDog =3D 0; // sets the pointer to null // . . . delete pDog; // harmless -------------------------------------------------------------------------= ------- But it does not work that way. As a matter of fact with both the = Bloodshed/GNU compiler supplied with the book and VC++ 6.0 it works just = the opposite. The book uses this program to demonstrate allocating and = deleting a pointer.=20 -------------------------------------------------------------------------= ------- // Listing 9.4 // Allocating and deleting a pointer #include <iostream> int main() { int localVariable =3D 5; int * pLocal=3D &localVariable; int * pHeap =3D new int; if (pHeap =3D=3D NULL) { std::cout << "Error! No memory for pHeap!!"; return 1; } *pHeap =3D 7; std::cout << "localVariable: " << localVariable << "\n"; std::cout << "*pLocal: " << *pLocal << "\n"; std::cout << "*pHeap: " << *pHeap << "\n"; delete pHeap; pHeap =3D new int; if (pHeap =3D=3D NULL) { std::cout << "Error! No memory for pHeap!!"; return 1; } *pHeap =3D 9; std::cout << "*pHeap: " << *pHeap << "\n"; delete pHeap; return 0; } =20 -------------------------------------------------------------------------= ------- If you compile and run the program the output is as advertised in the = book; localVariable: 5 *pLocal: 5 *pHeap: 7 *pHeap: 9 However if you modify the code by setting pHeap to null and call delete = on pHeap immedately after as shown below. The program still runs without = error.=20 -------------------------------------------------------------------------= ------- // Listing 9.4 // Allocating and deleting a pointer #include <iostream> int main() { int localVariable =3D 5; int * pLocal=3D &localVariable; int * pHeap =3D new int; if (pHeap =3D=3D NULL) { std::cout << "Error! No memory for pHeap!!"; return 1; } *pHeap =3D 7; std::cout << "localVariable: " << localVariable << "\n"; std::cout << "*pLocal: " << *pLocal << "\n"; std::cout << "*pHeap: " << *pHeap << "\n"; delete pHeap; delete pHeap; // Try to crash program pHeap =3D new int; if (pHeap =3D=3D NULL) { std::cout << "Error! No memory for pHeap!!"; return 1; } *pHeap =3D 9; std::cout << "*pHeap: " << *pHeap << "\n"; delete pHeap; return 0; } -------------------------------------------------------------------------= ------- If set pHeap to null, however, and then try to assign *pHeap a value, as = shown below, the program will crash.=20 -------------------------------------------------------------------------= ------- // Listing 9.4 // Allocating and deleting a pointer #include <iostream> int main() { int localVariable =3D 5; int * pLocal=3D &localVariable; int * pHeap =3D new int; if (pHeap =3D=3D NULL) { std::cout << "Error! No memory for pHeap!!"; return 1; } *pHeap =3D 7; std::cout << "localVariable: " << localVariable << "\n"; std::cout << "*pLocal: " << *pLocal << "\n"; std::cout << "*pHeap: " << *pHeap << "\n"; pHeap =3D 0; *pHeap =3D33; pHeap =3D new int; if (pHeap =3D=3D NULL) { std::cout << "Error! No memory for pHeap!!"; return 1; } *pHeap =3D 9; std::cout << "*pHeap: " << *pHeap << "\n"; delete pHeap; return 0; } -------------------------------------------------------------------------= ------- I have several questions. 1.. How could someone who is expert enough to write a beginning book = on C++ make such an error=20 2.. Is it perhaps because the ANSI/ISO definition of the language = and what a compiler should do has changed?=20 3.. Have GNU and the Gates crowd made similar unilateral changes to = solve a pesky problem?=20 4.. Did I misread something which seems fairly straight forward?=20 5.. Are there other pointer inconsistances hiding in the weeds = waiting to pounce on the unsuspecting? |