Libzypp/Design/Exceptions

Şuraya atla: kullan, ara

Nesneler ve Özel durumlar Hakkında.

ResObject değil, fakat herhangi C++ nesnesi (Sınıf).Bir nesne yapılandırılır, kullanılır ve artık ihtiyaç olmadığında silinir (umarız). Bunda hiç yeni birşey yok fakat gerçekten ne olduğunu düşünelim:

//---------------------------------
struct Foo : public Base
{
Foo()
: _data( 0 )
{
// ctor code <=== What happens here?
}

~Foo()
{
// dtor code <=== What happens here?
}

Type _data;
};

Foo f;  <=== What happens here?
//---------------------------------

Mesela bir Foo yapılıyor bir kez olduktan sonra silininceye kadar onu kullanabilirsiniz.


Fakat ctor koduna bakın: Foo nesnesi halihazırda burada var mı?

Derleyici zaten Foo için yer belirlemiş oluyor. Temel sınıflar başlatılıyor, _veri üyeleri yaratılıyor ve başaltılıyor.

dtor kodu içinde aynısı yapılıyor: Foo nesnesi halen var mı?

Hala erişilebilir veriler ve temel sınıflar var.


İki soruya da cevap verin:

NO IT DOES NOT!
NO IT DOES NOT!

Eğer ÖZEL DURUMLARI KULLANIYORSANIZ bunu HATIRLAMAK ÇOK ÖNEMLİ.

Kurallar

Eğer hiç özel durum yoksa, ctor ve dtor kodları geri dönecektir ve sonra ya varolur ya da gitmiş olur.


Kabataslak:

= SON CTOR DÖNDÜĞÜNDE varolan nesne.

=

= ve İLK DTOR ÇAĞRILIR ÇAĞRILMAZ gidiyor .

=

= yakalanamayan bir özel durum NO RETURN.

=

= NO DTOR'un VAROLMAYAN NESNELER için çağrısı.

=

= YIĞINI hatırlatan bir try.

=

= YIĞINI geriye döndüren bir catch.

=

Bunu bilmek neden çok önemli?

= ASLA bir ÖZEL DURUMUN bir DTOR'a KAÇMASINA izin vermeyin

=

Okumak isteyeceğinizden ve benim açıklayabileceğim daha fazla nedenden dolayı çok önemli . If you dtor executes code that might throw, enclose it in TRY, and CATCH it.

= If an EXCEPTION ESCAPEs a CTOR, the OBJECT has NEVER EXISTED!

=

NO DTOR is CALLED.

Şu durumda yapamayacağınız bir şey, yaratılan objeden etraftaki diğer objeleri türetmek ve sonra atmak. Yaratmaya çalıştığınız nesne yok. Hiç bir zaman olmadı!

Ctor'da bazı diğer nesneleri sizin orada olduğunuzun farkına vardırmanız yakında varolacağınızın garantisidir .Tabii eğer onu yakalayarak ya da atarak bozmazsanız...

...Hayır, cezalandırılmayacaksınız. Asla varolmayan birşey için kimse cezalandırılmaz.Ancak simsiyah bir ekranın karşısında çok üzgün bir kullanıcı bırakabilirsiniz.

SO DO NOT DO THIS!

NOTE: NO DTOR is called for the object your about to create, this is the object in whichs ctor you are. For the Base classes and data members which already exist (inside the not yet existing object), their dtor is called!

This is why it so important, to care about things which must be undone (new/delete, open/close, lock/unlock,...). This is why RAII (Resource Acquisition Is Initialisation) is important and very helpfull.

(see. About exceptions.., posted Dec 07 on zypp-devel; here)

TRY and CATCH operate on the STACK

That's a not minor important thing to remember. And it does not apply to exceptions in ctors only.

Throwing an exception, the stack is unwound up to location of a previous try.

THIS IS NOT UNDO EVERYTHING I DID!

So if you do (or cause) something within an object, which is not correct in case your function throws, use e.g. RAII to undo it. (outside the ctor 'within an object' applies to 'this' as well)

So try to group the actions within a method or function, so that throwing stuff is done first, and once you're sure it will perform, start actually changing the state of objects.


For example, the lazy parsing of Source metadata into ResObjects:

The Source is already created, metadata were downloaded, first access to the ResStore:

Parsing starts, and may throw a parse exception. As we parse lazy (not in the ctor, where the exception would lead to noSource), The Source still exists after someone caught the exception.

What about the ResStore? If the parsers feed directly into the public Store, the Source is unsusable, as the Store offers partial content. This can't be. If parsing fails, the Store must stay empty.

(A SourceImpl task, to enforce this. I'll have a look at this over the weekend.

Exception is not like a boomerang! It won't hit you, if you throw it right. But like a boomerang it's easy to throw it wrong.


> But this ends with:
>
> <5> [DEFINE_LOGGROUP] Exception.cc(log):83
>     YUMSourceImpl.cc(YUMSourceImpl):94
>     THROW:    YUMSourceImpl.cc(YUMSourceImpl):94:
>     Cannot read repomd file, cannot initialize source
> <5> [DEFINE_LOGGROUP] ReferenceCounted.cc(~ReferenceCounted):37
>     ~ReferenceCounted: nonzero reference count
>terminate called after throwing an instance of 'std::out_of_range'
>  what():  ~ReferenceCounted: nonzero reference count

Fortunately Stano found this, so we have time ;) to review and think about the code we wrote. Esp. about exceptions used in Ctor, Dtor, and other methods.

The problem here is that the {{{YUMSourceImpl]]] ctor gives away at least one reference to itself, to some other object. But then decides not to exist by throwing an exception from the ctor.

YUMSourceImpl's base class ReferenceCounted, is already constructed. It exists inside YUMSourceImpl. Thus it's dtor is called. (~YUMSourceImpl is not called as it does not exist).

As some other object already holds a reference on YUMSourceImpl, the reference counter is not zero, as it is expected to be in the dtor of a ReferenceCounted object.

So the YUMSourceImpl ctor must not throw, after having passed a reference to 'this' to the outer world.


And after all this writing, you should be able to spot the 2nd and the 3rd fundamental bug revealed by these two loglines.


Fortunately, one may say.

Otherwise the calling code would have caught the YUMSourceImpl exception. And at sometime sowhere someone would have accessed the YUMSourceImpl, that never existed. Either the other object itself or the dtor of the reference given to the object (the _Ptr or _Ref).

And you all know how painfull it is, to hunt such a kind of bug.

2nd: ReferenceCounted dtor throws, and this leads to an exception within an exception. This is not catchable and terminates the application.

One of the reasons, why one should not let exceptions escape a dtor.

3rd: Exceptions are catchable, thus the application is able to ignore the error, and may continue. ReferenceCounted has to abort(), because the outstanding references to the deleted object WILL access it from their dtor (to decrease the refcount)

That's an internal error which must abort, so we are able to find it while testing. Too dangerous to stay undetected.


back ...

Trac'ta 'kkaempf' tarafından yapılan son düzeltme '02/04/06 14:01:18'


Trac'ta 'kkaempf' tarafından yapılan son düzeltme '02/04/06 14:01:18'


Trac'ta 'kkaempf' tarafından yapılan son düzeltme '02/04/06 14:01:18'


Trac'ta 'kkaempf' tarafından yapılan son düzeltme '02/04/06 14:01:18'