Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.

Konstruktor i izuzetak

[es] :: C/C++ programiranje :: Konstruktor i izuzetak

Strane: 1 2

[ Pregleda: 8272 | Odgovora: 29 ] > FB > Twit

Postavi temu Odgovori

Autor

Pretraga teme: Traži
Markiranje Štampanje RSS

rivan
Ivan Radovanović

Član broj: 1901
Poruke: 71
*.preco1990.com.

ICQ: 212235650


Profil

icon Re: Konstruktor i izuzetak20.10.2004. u 09:31 - pre 237 meseci
@Dragi Tata
Citat:
upotrebom standardnih kontejnera i pametnih pointera ubijemo više muva jednim udarcem: dobijemo exception-safe kod i ispravnu copy semantiku.

Kad to kazes impliciras da resenjem na gornji nacin neces imati ni exception-safe kod (a poenta je bila da gornji kod jeste exception-safe), ni ispravnu copy semantiku, sto jednostavno nije tacno

Citat:

Slažem se da ne postoje "univerzalno bolja" rešenja, ali ako su ti performanse izgovor da uopšte ne koristiš standardnu biblioteku, onda praviš veliku grešku koja se zove "Premature optimization". Otkud znaš da je rešenje sa golim pointerima brže nego sa vektorom?

Radi se o tome da tacnu semantiku tvoje klase znas samo ti (npr. znas da pomeranje niza objekata tvoje klase trpi i memcpy, a nema potrebe za pozivanjem operatora = ili copy konstruktora (ovo ne znaci da tvoja klasa ne sadrzi pointere)) pa ti mozes da napravis dinamicki niz koji ce se bolje ponasati od bilo kog template-a koji je pisan sa namerom da funkcionise u svim slucajevima.

Citat:

možeš da uradiš npr nešto ovako:

Code:

class a : boost::noncopyable {
    boost::scoped_array<char> an, bn;
public:
    a() : an(new char[1000]), bn(new char[1000000]) 
        {}
};



Tema je bila kako pisati kod koji nece imati curenja u konstruktoru - ti dajes predlog za kod koji opet ima probleme sa curenjem.

Sto se tice auto_ptr i slicnih template-a njihova primena je prilicno ogranicena na specificne slucajeve (prosledjivanje pointera kao parametara i slicno), a nikako ne predstavljaju neko univerzalno primenljivo resenje (kako bi tim zezalicama implementirao asocijacije medju objektima gde mogu da se jave i curkularne reference i ko zna sta jos?). Druga stvar o kojoj treba voditi racuna je da li ti znas kako je TACNO implementiran neki template u STL-u - npr. vector - koliko se secam jedino sto se garantuje je da je pristup proizvoljnom elementu O(1) operacija - ali nisu svi O(1) uvek bas to - ako je vector napisan tako da cuva niz pointera na svoj sadrzaj (npr. da bi se izbeglo cesto pozivanje copy konstruktora pri produzavanju) ti imas O(1) pri pristupu elementima i potencijalno lose performanse pri maloj kolicini slobodne fizicke memorije u zavisnosti od redosleda kojim su kreirani objekti (moze da izaziva veliki broj page fault-ova iako je kolicina memorije zauzeta tim objektima mozda mala).

Poenta onog sto hocu da kazem je da ne treba izbegavati pointere (ako hoces da radis bez njih imas c# i javu), i da ne treba koristiti STL po svaku cenu (nema puno smisla izmisljati toplu vodu ako neki STL template radi TACNO ono sto ti treba i to onako kako ti hoces).

Nisam hteo da davim (iako se malo oteglo), samo da predstavim drugu stranu medalje...
 
Odgovor na temu

Dragi Tata
Malo ispod Kanade

Član broj: 1958
Poruke: 3906
66.228.70.*



+6 Profil

icon Re: Konstruktor i izuzetak20.10.2004. u 13:27 - pre 237 meseci
Citat:
rivan:
upotrebom standardnih kontejnera i pametnih pointera ubijemo više muva jednim udarcem: dobijemo exception-safe kod i ispravnu copy semantiku.

Kad to kazes impliciras da resenjem na gornji nacin neces imati ni exception-safe kod (a poenta je bila da gornji kod jeste exception-safe), ni ispravnu copy semantiku, sto jednostavno nije tacno


Ne impliciram ništa, samo kažem da ćemo uz mnogo manje rada (i mnogo manje mogućnosti da zajebemo nešto) da dobijemo exception-safe kod i ispravnu copy semantiku uz malo ili nimalo penala u performansama ako koristimo pametne pointere na način na koji sam to pokazao.


Citat:
rivan:
Radi se o tome da tacnu semantiku tvoje klase znas samo ti (npr. znas da pomeranje niza objekata tvoje klase trpi i memcpy, a nema potrebe za pozivanjem operatora = ili copy konstruktora (ovo ne znaci da tvoja klasa ne sadrzi pointere)) pa ti mozes da napravis dinamicki niz koji ce se bolje ponasati od bilo kog template-a koji je pisan sa namerom da funkcionise u svim slucajevima.


Možeš, ne kažem da ne možeš. Kažem samo da najčešće nemaš potrebe to da radiš. Osnovni princip je da prvo napraviš program koji radi ispravno, onda meriš performanse i optimizuješ uska grla. U trenutku kad dizajniraš klase najčešće ne znaš gde su uska grla i najčešće je bolje da koristiš pouzdana i jednostavna rešenja da program lepo proradi.

Citat:
rivan:
Tema je bila kako pisati kod koji nece imati curenja u konstruktoru - ti dajes predlog za kod koji opet ima probleme sa curenjem

Može biti da mi je nešto promaklo, ali ne vidim da ovaj primer ima problema sa curenjem. Na šta misliš?

Citat:
rivan:
Sto se tice auto_ptr i slicnih template-a njihova primena je prilicno ogranicena na specificne slucajeve (prosledjivanje pointera kao parametara i slicno), a nikako ne predstavljaju neko univerzalno primenljivo resenje

Upravo obrnuto. Pametni pointeri su napravljeni i polako se uvode u standard da bi zamenili gole pointere osim u specifičnim slučajevima gde to nije moguće ili svrsishodno.

Citat:
rivan:
kako bi tim zezalicama implementirao asocijacije medju objektima gde mogu da se jave i curkularne reference i ko zna sta jos?).

Cirkularne reference se probijaju "slabim pointerima" u koje spadaju i sirovi pointeri - to najčešće nije problem. Kad jeste, može da se koristi neki nedeterministički GC kao što je Boehm-ov. Napominjem da u takvim slučajevima ni sirovi pointeri ne mogu da reše situaciju.

Citat:
rivan:
Poenta onog sto hocu da kazem je da ne treba izbegavati pointere (ako hoces da radis bez njih imas c# i javu), i da ne treba koristiti STL po svaku cenu (nema puno smisla izmisljati toplu vodu ako neki STL template radi TACNO ono sto ti treba i to onako kako ti hoces).

C# i Java imaju svoj način rešavanja problema sa curenjem memorije koji opet uvodi neke druge probleme, uglavnom taj način je dosta drugačiji od pametnih pointera u C++u i poređenje nije baš na mestu. Uglavnom, nikad nisam rekao da STL treba koristiti po svaku cenu (to bi bilo prilično glupavo sa moje strane) ali "po defaultu" najčešće treba izabrati standardne kontejnere i pametne pointere, a ne sirove - dobit u pouzdanosti programa i produktivnosti je velika a cene u performansama su ili male ili nikakve.

Citat:
rivan:
Nisam hteo da davim (iako se malo oteglo), samo da predstavim drugu stranu medalje...


Neka, neka. Lepo je "advokatisati" oko pametnih stvari za promenu ;)
 
Odgovor na temu

rivan
Ivan Radovanović

Član broj: 1901
Poruke: 71
*.preco1990.com.

ICQ: 212235650


Profil

icon Re: Konstruktor i izuzetak20.10.2004. u 14:39 - pre 237 meseci
Citat:

Može biti da mi je nešto promaklo, ali ne vidim da ovaj primer ima problema sa curenjem. Na šta misliš?

Code:

class a : boost::noncopyable {
    boost::scoped_array<char> an, bn;
public:
    a() : an(new char[1000]), bn(new char[1000000]) 
        {}
};

Zamisli da se desi exception prilikom alokacije bn - nece ti pomoci cinjenica da si koristio template a ne obicni pointer za an radi toga sto nece biti pozvan destruktor ni za a, a samim ti ni za objekte koje a sadrzi - u slucaju da se desi exception u konstruktoru ne poziva se destruktor...
Citat:

C# i Java imaju svoj način rešavanja problema sa curenjem memorije koji opet uvodi neke druge probleme, uglavnom taj način je dosta drugačiji od pametnih pointera u C++u i poređenje nije baš na mestu.

Ako je zabijanje glave u pesak sve dok se ne ostane skroz, ili bez 1/2 memorije, ako tako bese rade ti gc-ovi sa obilazenjem i kopiranjem, neko resavanje problema onda je definitivno bolje sto niko nije pokusao da u c++ "resi" problem na isti nacin

Mislim da smo na kraju prilicno razjasnili stvari...
 
Odgovor na temu

Dragi Tata
Malo ispod Kanade

Član broj: 1958
Poruke: 3906
66.228.70.*



+6 Profil

icon Re: Konstruktor i izuzetak20.10.2004. u 14:54 - pre 237 meseci
Citat:
rivan
Zamisli da se desi exception prilikom alokacije bn - nece ti pomoci cinjenica da si koristio template a ne obicni pointer za an radi toga sto nece biti pozvan destruktor ni za a, a samim ti ni za objekte koje a sadrzi - u slucaju da se desi exception u konstruktoru ne poziva se destruktor...


Grešiš; a će da se "počisti". Ako ne veruješ, probaj ovo:

Code:

#include <memory>
#include <iostream>
using namespace std;

class C {
        int broj_;
public:
    C(bool baci, int broj):broj_(broj) 
        {
        if (baci)
            throw 1;
        cout << "Inicijalizovan " << broj_ << "\n";
        }
    ~C()
        {
        cout << "Skemban " << broj_ << "\n";
        }
    };

class D {
    auto_ptr<C> a, b;
public:
    D() : a(new C(false, 1)), b(new C(true, 2))
            {}
    };

int main (void)
    {
    try
        {
        D d;
        }
    catch (int i)
        {
        }
    }


Rezultat:

Inicijalizovan 1
Skemban 1
Press any key to continue

Citat:
rivan:
Ako je zabijanje glave u pesak sve dok se ne ostane skroz, ili bez 1/2 memorije, ako tako bese rade ti gc-ovi sa obilazenjem i kopiranjem, neko resavanje problema onda je definitivno bolje sto niko nije pokusao da u c++ "resi" problem na isti nacin


Složio bih se sa tobom, ali ne smem - Relja će da me bije ;)
 
Odgovor na temu

rivan
Ivan Radovanović

Član broj: 1901
Poruke: 71
*.ppp-bg.sezampro.yu.

ICQ: 212235650


Profil

icon Re: Konstruktor i izuzetak20.10.2004. u 15:42 - pre 237 meseci
Interesantno bi bilo to probati na vise kompajlera - mislim da standard to pitanje ostavlja nedefinisano...
 
Odgovor na temu

Dragi Tata
Malo ispod Kanade

Član broj: 1958
Poruke: 3906
66.228.70.*



+6 Profil

icon Re: Konstruktor i izuzetak20.10.2004. u 15:48 - pre 237 meseci
Pogledaću u standardu kad budem stigao, a u međuvremenu evo šta kaže GCC:


% vi konstruktori.cpp
% g++ konstruktori.cpp -okonstruktori
% ./konstruktori
Inicijalizovan 1
Skemban 1
% g++ -v
Reading specs from /opt/gcc.3.3/lib/gcc-lib/i586-pc-interix3/3.3/specs
Configured with: : (reconfigured) : (reconfigured) /dev/fs/C/gnu2.intel/egcs.source//configure --verbose --prefix=/opt
/gcc.3.3 --disable-shared --with-stabs --enable-nls --with-local-prefix=/opt/gcc.3.3 --with-gnu-as --with-gnu-ld --enabl
e-targets=i586-pc-interix3 --enable-threads=posix
Thread model: posix
gcc version 3.3
%

 
Odgovor na temu

rivan
Ivan Radovanović

Član broj: 1901
Poruke: 71
*.preco1990.com.

ICQ: 212235650


Profil

icon Re: Konstruktor i izuzetak21.10.2004. u 07:26 - pre 237 meseci
Citat:
rivan: Interesantno bi bilo to probati na vise kompajlera - mislim da standard to pitanje ostavlja nedefinisano...

Nisam bio u pravu - standard kaze da se ti objekti unistavaju automatski - ja sam probao na gcc 2.95.4, 3.2.3, MS c++ 13.10 i svud radi ovako kako si napisao :-)

P.S.
ima jedna interesantna stvar u kodu koji smo pisali - a to je upotreba inicijalizacionih lista - ono sto mnogim ljudima promice je da je redosled izvrsavanja inicijalizacija u listi isti kao redosled definisanja atributa u definiciji klase - dakle i sledeci kod radi potpuno isto kao i originalni
Code:

class D {
    auto_ptr<C> a, b;
public:
    D() : b(new C(true, 2)), a(new C(false, 1))
            {}
    };

 
Odgovor na temu

Dragi Tata
Malo ispod Kanade

Član broj: 1958
Poruke: 3906
66.228.70.*



+6 Profil

icon Re: Konstruktor i izuzetak21.10.2004. u 14:09 - pre 237 meseci
Citat:
rivan: ono sto mnogim ljudima promice je da je redosled izvrsavanja inicijalizacija u listi isti kao redosled definisanja atributa u definiciji klase


Da. Meyers je dao lep primer kako ovo može da "ujede":

Code:

class MyClass
{
  Foo myFoo;
  long lval;
public:
  MyClass( ) : lval(125), myFoo(lval) {}
};


Čupav ovaj C++, nema šta, hehehe. Na žalost, nisam mu našao dostojnu zamenu.
 
Odgovor na temu

Dragi Tata
Malo ispod Kanade

Član broj: 1958
Poruke: 3906
*.bos.east.verizon.net.



+6 Profil

icon Re: Konstruktor i izuzetak24.10.2004. u 03:17 - pre 237 meseci
Da zašećerim ovu lepu raspravu "guruom nedelje 67"

http://www.gotw.ca/gotw/066.htm

Citat:

Moral #1: Constructor function-try-block handlers have only one purpose -- to translate an exception. (And maybe to do logging or some other side effects.) They are not useful for any other purpose.

Moral #2: Since destructors should never emit an exception, destructor function-try-blocks have no practical use at all.[6] There should never be anything for them to detect, and even if there were something to detect because of evil code, the handler is not very useful for doing anything about it because it can not suppress the exception.

Moral #3: Always perform unmanaged resource acquisition in the constructor body, never in initializer lists. In other words, either use "resource acquisition is initialization" (thereby avoiding unmanaged resources entirely) or else perform the resource acquisition in the constructor body.

For example, building on Example 2(b), say T was char and t_ was a plain old char* that was new[]'d in the initializer-list; then in the handler there would be no way to delete[] it. The fix would be to instead either wrap the dynamically allocated memory resource (e.g., change char* to string) or new[] it in the constructor body where it can be safely cleaned up using a local try-block or otherwise.

Moral #4: Always clean up unmanaged resource acquisition in local try-block handlers within the constructor or destructor body, never in constructor or destructor function-try-block handlers.

Moral #5: If a constructor has an exception specification, that exception specification must allow for the union of all possible exceptions that could be thrown by base and member subobjects. As Holmes might add, "It really must, you know." (Indeed, this is the way that the implicitly generated constructors are declared; see GotW #69.)

Moral #6: If a constructor of a member object can throw but you can get along without said member, hold it by pointer and use the pointer's nullness to remember whether you've got one or not, as usual. Use the Pimpl idiom to group such "optional" members so you only have to allocate once.

And finally, one last moral that overlaps with the above but is worth restating in its own right:

Moral #7: Prefer using "resource acquisition is initialization" to manage resources. Really, really, really. It will save you more headaches than you can probably imagine.

 
Odgovor na temu

mipko

Član broj: 11015
Poruke: 109
*.sbb.co.yu.



Profil

icon Re: Konstruktor i izuzetak08.11.2004. u 09:03 - pre 236 meseci
Kad vec pricamo o izuzecima treba pomenuti jos dve vrlo neprijatne zamke:

1. unexpected exceptions
2. exception u destructoru

Licno mislim da su exceptions dobar mehanizam za kontrolu gresaka. Ali zahteva jako dobro razumevanje.


pozdrav
Mirko
 
Odgovor na temu

[es] :: C/C++ programiranje :: Konstruktor i izuzetak

Strane: 1 2

[ Pregleda: 8272 | Odgovora: 29 ] > FB > Twit

Postavi temu Odgovori

Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.