Post #267,088
9/8/06 9:46:36 PM
|
Exceptions are key
toss one and all the stack object destructors will get called as the stack unwinds. Toss something unique that nothing will catch. Mind you - only stack object destructors will get called.
C-isms like goto, various jump tricks like switch/case, etc do not work with the exception system and you can jump past a destructor call point.
[link|http://www.blackbagops.net|Black Bag Operations Log]
[link|http://www.objectiveclips.com|Artificial Intelligence]
[link|http://www.badpage.info/seaside/html|Scrutinizer]
|
Post #267,091
9/8/06 10:03:36 PM
|
Thanks
|
Post #267,139
9/9/06 8:44:43 PM
9/9/06 8:49:24 PM
|
How's this:
Ok, here is what I got so far. It works, and the object destructor is called when it goes out of scope. \nstruct ES{\n\tstring p;\n\tES(string q) { p = q; }\n};\n\n// code snip\n...\n// code snip\n\n\n\ttry{\n\t\t// Create a bare block to scope the lock so\n\t\t// it is destroyed automatically\n\t\t{\n\t\t\tLock_File lock = get_lock(id_file);\n\t\t\tint last_count_int = get_current_seq(id_file);\n\t\t\tint new_count = last_count_int + requested_count;\n\t\t\twrite_new_seq(new_count, id_file);\n\t\n\t\t\t//\n\t\t\t// Parent program is expecting this exact format, do NOT change it\n\t\t\t//\n\t\t\tcout << "Range: " << (last_count_int + 1) << " " << new_count << endl;\n\t\t}\n\t\texit(0);\n\t} // end try\n\tcatch (ES e){\n\t\tmy_die(e.p);\n\t}\n\tcatch (...){\n\t\tmy_die("Unknown error");\n\t}\n\n Any of the called functions can throw ES("Some text"). Can it be done any better / simpler / cleaner?
Edited by broomberg
Sept. 9, 2006, 08:49:24 PM EDT
|
Post #267,161
9/10/06 12:27:04 PM
|
A Mantra in C++ - Construction is Resource Acquisition
It is the practice of using object lifecycles to manage resource acquisition/release. Lock_File lock = get_lock(id_file); I'm guessing Lock_File (ugly naming convention - the rest of the world would call it LockFile) is a class. Why have a get_lock function? It is probably constructing/then copying the Lock_File object - which means is probably doesn't work right. \nclass LockFile\n{\npublic: \n LockFile(int fileId) { /*get the lock if you can, throw if you can't */}\n ~LockFile() { /* release the lock */ }\nprivate: /* prevent some accidents */\n LockFile(const LockFile&) {}\n LockFile& operator=(const LockFile&) {}\n);\n now to acquire a lock LockFile lock(file_id); Your ES constructor uses assignment - you should get in the habit of using initialization because your version can result in 2 copies where mine below results in one if its called with a string, 2 with a const char*. ES(const string& q) : p(q) {} to eliminate the extra copy - overload it: ES(const char* s) : p(s) {} will construct one string total - most efficient version. I'd probably also make Sequence a thing with an operator int() and that fetches the new sequence number and increments everytime you use it - but that is a bit fancy for this.
[link|http://www.blackbagops.net|Black Bag Operations Log]
[link|http://www.objectiveclips.com|Artificial Intelligence]
[link|http://www.badpage.info/seaside/html|Scrutinizer]
|
Post #267,163
9/10/06 1:41:55 PM
|
Thanks
I actually did a bit of what you said already this morning. The usage for the function get_lock was because I hadn't fully started using exceptions yet, which in turn meant I wanted a local function to check that the object had created the lock file, and it did it by checking to see if the object's file descriptor was not -1. So, added a throw to the Lock_File object constructer, get rid of the front end code that checks the value, and get rid of the method that provides it. Lock_File -> LockFile - check. Assignment changed to initialization, overloaded added - check. \nLockFile(const LockFile&) {}\n This is a constructor that takes an argument of an address of a LockFile object. But what does it actually do? \nLockFile& operator=(const LockFile&) {}\n This is an override of an equals that returns is address of the LockFile object - right?
|
Post #267,175
9/10/06 10:26:41 PM
|
2 of the "magic 4" methods
Copy constructor: LockFile(const LockFile&) {} is generated by the compiler if you don't write it. The compiler version does a memberwise copy (calling copy ctors of all embedded objects). Consider this code: \nclass LockFile\n{\npublic: \n LockFile(int fileId) : _lock(primitiveCreateLockFileFunction(fileId)) {}\n ~LockFile() { primitiveReleaseLock(_lock); }\nprivate: \n int _lock;\n};\n\nfunc(LockFile lock) {}\n....\nLockFile lock(aFileId);\n\nfunc(lock); // object is copied via the copy constructor - at end of function it is destroyed - releasing the lock\n See the problem? A for the duration of func, there are two copies of the lock object - one passed to func, the other in the calling stack frame. They end up sharing the same lock and your lock gets free'd early. There are two fixes to this 1) Always pass lock by reference. 2) Make FileLock's copy ctor private so the compiler will prevent unintentional copying since you haven't made the object copy safe. The second method is similar, but used in assignment and once again, the compiler will generate it for you if you don't. You should always define the "big 4" methods and, if you can't make some of them safe, make them private so nothing can call them.
[link|http://www.blackbagops.net|Black Bag Operations Log]
[link|http://www.objectiveclips.com|Artificial Intelligence]
[link|http://www.badpage.info/seaside/html|Scrutinizer]
|
Post #267,178
9/10/06 10:50:17 PM
|
Ahh, thanks
My original code used a new and passed the pointer around, but had a bunch of work for no reason. My new "simplified" code only did the single allocation, didn't copy anything around, so was bug free by accident.
I would have noticed the accidental destroy since I was printing a message when called, trying to understand it. But again, pure luck.
I've got the 3rd edition of the C++ Programming Language that I've been reading, but it is slow going.
And 'ctor'? That took a bit of googling to figure out it was shorthand for constructor. You must be used to it.
|
Post #267,205
9/11/06 12:25:30 PM
|
If you are going to continue on this path
You really ought to get (and read) Scott Meyer's [link|http://www.amazon.com/Effective-C%2b%2b-Addison-Wesley-Professional-Computing/dp/0321334876/sr=8-1/qid=1157991837/ref=pd_bbs_1/104-0140589-9124705?ie=UTF8&s=books|Book] "Effective C++".
It explains all this stuff in nice easy to read bite sized chunks.
[link|http://www.blackbagops.net|Black Bag Operations Log]
[link|http://www.objectiveclips.com|Artificial Intelligence]
[link|http://www.badpage.info/seaside/html|Scrutinizer]
|
Post #267,243
9/11/06 5:09:10 PM
|
Order request sent
Thanks
Note: One of my favorite Perl book is Effective Perl programming, which I believe is patterned after this book (or maybe the C one).
|
Post #267,352
9/12/06 3:39:15 PM
|
Ordered from big river today.
|
Post #267,164
9/10/06 1:51:43 PM
|
Oh, and as far as using it for a sequence at a time,
it doesn't follow the workflow.
The goal of this program is to be called from a data processing shell script. It is provides a contiguous range of usable unique ids.
So:
#1 - Check for input files. #2 - Count input files - "wc -l" or some such #3 - Call get_id_range, telling it how many you need #4 - get_id_range figures out last highest used, and lets you know what the next available range is, in $LOW and $HIGH. It writes the highest in the file for the next invocation. It keeps the file locked during the process to make sure a simultaneous run does not hurt it. The lock is nothing more than the same file name with .lck added. This allows network mounted files to work when there is not a lock manager avaiable for real locking. #5 - cat *.dat | preprend_id $LOW $HI >new_data_file_with_sequences.dat #6 - Profit!
|
Post #267,235
9/11/06 4:30:42 PM
|
OK - but I would be likely to model seq as iterator
[link|http://www.blackbagops.net|Black Bag Operations Log]
[link|http://www.objectiveclips.com|Artificial Intelligence]
[link|http://www.badpage.info/seaside/html|Scrutinizer]
|
Post #267,231
9/11/06 3:54:23 PM
|
What. He. Said.
(Todd, for someone with so much obvious disdain for the language, you're quite well current on it's subtleties.)
jb4 "So don't pay attention to the approval ratings that say 68% of Americans disapprove of the job this man is doing. I ask you this, does that not also logically mean that 68% approve of the job he's not doing? Think about it. I haven't." — Stephen Colbert, at the White House Correspondent's Dinner 29Apr06
|
Post #267,233
9/11/06 4:08:42 PM
|
You can't properly hate something you don't really know
===
Purveyor of Doc Hope's [link|http://DocHope.com|fresh-baked dog biscuits and pet treats]. [link|http://DocHope.com|http://DocHope.com]
|
Post #267,249
9/11/06 7:41:32 PM
|
Disagree.
Never met, nor do I claim to "really know" Der Berk. Doesn't keep me from having a level of disdain for his person that is indistinguisable from the sort of hate that Todd professes for C++ ....
jb4 "So don't pay attention to the approval ratings that say 68% of Americans disapprove of the job this man is doing. I ask you this, does that not also logically mean that 68% approve of the job he's not doing? Think about it. I haven't." — Stephen Colbert, at the White House Correspondent's Dinner 29Apr06
|
Post #267,254
9/11/06 8:03:04 PM
|
Disagree with your disagree.
You really do know as much as you need to.
|
Post #267,234
9/11/06 4:24:25 PM
|
That's just the problem
Most C++ coders are not qualified to work in it. I reckon I am, but I don't like to work with incompetent people (who does?). C++ has a way of making nearly everybody incompetent. See how that works?
I will say that my knowledge hasn't been updated since about '97 and I'm not too familliar with the Boost stuff and it was the rise of template meta programming that convinced me that the few people who were capable of using the language had been driven insane by doing it. :-)
I reckon I've earned the right to hate it.
[link|http://www.blackbagops.net|Black Bag Operations Log]
[link|http://www.objectiveclips.com|Artificial Intelligence]
[link|http://www.badpage.info/seaside/html|Scrutinizer]
|