January 27, 2006
>> I know, I should have
>> used C++ exceptions, which I hope to do when we get more time on our
>> hands... (probably never :S)
>
> I'm not sure about that. This is a logical error, and ideally it would be caught at compile time. I think an assert is the next best option. (Because even if the exception is caught, there's still a logic error).

I mean in the case of such a Lock call, where a return value of "false" means the lock failed and you shouldn't do anything with the object. That's way to important to do with a return value and should be an exception that can't simply be forgotten about.

> I'm a little biased against exceptions, because the worst bug I've ever encountered in my life was caused by a destructor which threw an exception, inside a multi-threaded program. (There were virtually no symptoms, that single thread just silently disappeared - yikes).

Simple rule: never throw in a dtor :-)

Lio.


January 28, 2006
Sean Kelly wrote:
> Don Clugston wrote:
> 
>>
>> I'm a little biased against exceptions, because the worst bug I've ever encountered in my life was caused by a destructor which threw an exception, inside a multi-threaded program. (There were virtually no symptoms, that single thread just silently disappeared - yikes).
> 
> 
> That in itself is basically an illegal operation in C++, since throwing an exception while another is in flight terminates the program.

I know. The problem in this case was, (a) the destructor was calling a function which called another function (written by someone else) which eventually threw a destructor (it was not documented that it could throw), and
(b) if it terminated the program, that would be OK. In this case, it only terminated the thread. Causing a sequence of further disasters.

  If in
> doubt, wrap the contents of your dtor in a try{}catch(...){} block, and report the error by some other means.

I learnt from this to _always_ be in doubt. It left me with in serious doubt of the merits of RAII when used with exceptions. It means that any kind of cleanup operation cannot use exceptions to report errors.


  I'll admit I do like that D
> doesn't have this problem, even if it means that some exceptions are overridden by others and are therefore never reported.  I've wondered whether exception chaining via the .next property might be right for this purpose, but it's not a perfect fit.
> 
> 
> Sean
January 31, 2006
Oskar Linde wrote:
> Lionello Lunesu wrote:
> 
>> Hi,
>>
>> This really should go in a C++ newsgroup, but I've noticed that I have more in common with the people here than on a C++ group. Must be all the frustrations with C/C++ and the hope for a better tomorrow. More than hope, an actual vision ; )
>>
>> Here's a construct I can't seem to get right in C++. It works, but I hate the way I've implemented it. Maybe somebody has a better idea?
>>
>> It starts like this: I convert some handle into a class to make use of C++'s RAII, ctor/dtor. I do this all the time, but today it happens to be for sqlite3_get_table / sqlite3_free_table. Needless to say, the handle (char**) obtained by sqlite3_get_table must be freed by sqlite3_free_table. The wrapper for this table handle I've called SqliteRS (from Result Set):
>>
>> class SqliteRS
>> {
>>   char** table;
>>   unsigned int cursor, rows, columns;
>> public:
>>   SqliteRS(char** t, int c, int r) : table(t), cursor(c), columns(c), rows(r) {}
>>   ~SqliteRS() { sqlite3_free_table(table); }
>> ....
>> };
>>
>> And you obtain an SqliteRS by calling Exec of the class SqliteDB, which wraps the database handle, sqlite3* (error handling omitted):
>>
>> SqliteRS SqliteDB::Exec( const char* zSql )
>> {
>>   sqlite3_get_table(pdb, zSql, &t, &r, &c, NULL );
>>   return SqliteRS(t,c,r);
>> }
>>
>> All this to be able to do:
>>
>> SqliteRS results = database.Exec("select * from X");
>>
>> And everything should be freed nicely.
>> The problem of course is that the temporary return value will actually be copied into the variable "results", causing the table to be freed when the temporary return value gets destructed, leaving "results" with an invalid handle. This is the problem I'm trying to solve.
> 
> 
>> At the moment I have two ways around this:
>>
>> 1) create a copy ctor that steals the pointer (sets it to NULL in the temporary return value); or
>> 2) create a seperate class for the return value and a ctor that takes this class in SqliteRS.
> 
> 
> [snip]
> 
>> Returning handles from other functions / factories happens only too often, and wrapping these handles in a class to make use of RAII (ctor/dtor) seems the way to go. But why is this contruction so tricky to do nicely? Am I forgetting something?
> 
> 
> This is what std::auto_ptr<> is perfect for. An auto_ptr will, using your words, steal the reference being assigned to it. A auto_ptr is perfect when you want to transfer responsibility.
> 
>> In D the class will be created on the heap and you're returning the handle of the class, so there's never a copy involved. One can even use RAII:
>>
>> class SqliteDB
>> {
>> ....
>>   SqliteRS Exec( char[] sql ) { .... return new SqliteRS(...); }
>> }
>>
>> auto SqliteRS result = database.Exec("...");
> 
> 
> Yes, but with this, the user needs to remember to make the reference auto. There is (AFAIK) no way in D to make this automatic like the c++ auto_ptr does. 
> 
> /Oskar

What do you mean "automatic like the c++ auto_ptr" ? What exactly are the differences? In C++ you must also make the reference an auto_ptr,no?

-- 
Bruno Medeiros - CS/E student
"Certain aspects of D are a pathway to many abilities some consider to be... unnatural."
January 31, 2006
In article <dro5lt$14bf$1@digitaldaemon.com>, Bruno Medeiros says...

>Oskar Linde wrote:
>>> auto SqliteRS result = database.Exec("...");
>> 
>> 
>> Yes, but with this, the user needs to remember to make the reference auto. There is (AFAIK) no way in D to make this automatic like the c++ auto_ptr does.
>> 
>> /Oskar

>What do you mean "automatic like the c++ auto_ptr" ? What exactly are the differences? In C++ you must also make the reference an auto_ptr,no?

Yes, but you can not by mistake make it a SqliteRS * if the function is defined to return an auto_ptr<SqliteRS>. In D, if you forget the auto, everything will compile and run, but the resources are not guaranteed to be freed.

/Oskar


February 01, 2006
I'm still not clear on this issue. Please tell me how you people solve the "using RAII for returned handles" problem.

Do you use...

a) method 1 from my original post: a wrapper with a copy ctor that steals
the pointer
b) method 2 from my original post: a separate class to temporarily wrap the
return value
c) std::auto_ptr<> and therefor a wrapped pointer on the heap
d) making the factory class a friend of the wrapper class

...there are probably even more ways to do this thing. RAII (however bad that name may be) is the best thing that OO languages have to offer (if you ask me) but it frustrates me that I can't find a nice solution for transfering handle-ownership from a factory the handle-wrapper.

Lionello.


1 2
Next ›   Last »