View mode: basic / threaded / horizontal-split · Log in · Help
January 27, 2006
Re: [OT] efficient return values
>> 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
Re: [OT] efficient return values
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
Re: [OT] efficient return values
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
Re: [OT] efficient return values
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
Re: [OT] efficient return values
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.
Next ›   Last »
1 2
Top | Discussion index | About this forum | D home