ot vesso(7-08-2005)

reiting (30)   [ dobre ]  [ zle ]

Printer Friendly Variant za otpechatvane

Primeren kod na cpp
/*
 *      Moderni metodi za upravlenie na pametta v C++
 *
 *   Edna ot osobenostite na C++ e che dava pochti pulen
 * kontrol na programista koga i kak da zadeli pamet i koga
 * i kak da ia osvobodi. S tozi kontrol idva i otgovornostta
 * da se osvobodi vsiako "parche" pamet koeto veche ne e nuzhno.
 * Kogato programata ne osvobozhdava pamet koiato veche ne e
 * nuzhna se poluchava "utechka na pamet" (memory leak).
 *
 *   Naposleduk ezitsi kato java, perl i python stanaha dosta
 * populiarni. Edno ot osnovnite im predimstva e che spestiavat
  * grizhite za upravlenie na pametta. S tiah programistite ne
triabva
  * polagat usiliia za osvobozhdavane na pamet koiato veche ne e
nuzhna.
 * Normalno e programist na C++, sled kato e zagubil polovin
  * den turseiki zashto programata mu konsumira vse poveche i
poveche
  * pamet, da zapochne taino da zavizhda na programistite
polzvashti
 * ezitsi ot po-visoko nivo.
 *
  *   S niakolko trika pochti pulno bezgrizhie pri upravlenieto
na
  * pametta mozhe da se postigne i v C++, pri koeto
programistut
  * postiga nai-dobroto ot dvata sviata - kompiliran "do
metala"
 * kod i izbiagvane na riskove ot utechki na pametta. TSelta na
  * tazi statiia e da zapozna chitatelia s tezi trikove.
Programistite
  * koito veche polzvat boost::shared_ptr (i znaiat zashto go
praviat)
  * edva li shte nauchat neshto novo - no tova ne bi triabvalo da
im prechi
 * da dadat glasa si za statiiata :-)
 *
  *   Statiiata ne e prednaznachena za absolyutno nachinaeshti.
Predpolaga
 * se che chitateliat ima bazovi poznaniia za C++, std::vector,
  * std::stream i drugi podobni. Po-naprednalite chitateli
mogat
 * da propusnat purvata polovina i da preskochat napravo do
 * sektsiiata za auto_ptr i shared_ptr.
 *
 *   Statiiata e oformena kato programa na C++ i mozhe da bude
  * kompilirana i izpulniavana stupka po stupka s tsel
postigane na
  * maksimalna iasnota. Kodut e pod litsenz GPL V2, a
avtorskite
 * prava sa na Veselin Kostadinov.
 *
  *   Statiiata-programa polzva bibliotekata boost, dostupna
za
 * svobodno polzvane ot www.boost.org. Bibliotekata se
  * instalira pod debian/ubuntu s "apt-get install
libboost-dev",
  * za drugi arhitekturi i kompilatori potursete informatsiia
na
 * tehniia sait.
 *
  *   Eto i samata programa. Purvo shte ni triabvat niakolko
header-a:
 */
 #include <iostream>
 #include <string>
 #include <vector>
 #include <sstream>
 #include <memory>
  #include
<boost/shared_ptr.hpp>

  // SHTe ni triabva i edin klas koito
da ni kazva kogato se suzdavat,
  // kopirat, izpolzvat i iztrivat
obekti:
 class my_class {
         private:
         std::string m_name;
         public:
          my_class(const
std::string& name): m_name(name)
          {std::cout << "creating
 '" << m_name << "'\n";}
          my_class(const
 my_class& other): m_name("copy of
" + other.m_name)
          {std::cout << "creating
 '" << m_name << "'\n";}
          ~my_class() {std::cout << "deleting '" << m_name <<
"'\n";}
          void use(const std::string & usage)
const
          {std::cout << "Using
 '" << m_name << "':
 " << usage << "\n";}
 };

  // SHTe ni triabvat i 2 funktsii s
koito da simulirame izpolzvane
  // na obekti: chrez referentsiia i
chrez ukazatel:
  void
use_by_reference(my_class & object)
 {
          object.use("from function
use_by_reference()");
 }

  void
use_by_pointer(my_class * object)
 {
          object->use("from function
use_by_pointer()");
 }

  //SHTe ni triabva i funktsiia koiato po
priavilo vrusha false
  //a po izklyuchenie: true
(http://en.wikipedia.org/wiki/Blue_moon)
  //Nie nabliagame na izklyucheniiata i
zatova ia priavim vinagi
 //da vrushta truer:
  bool is_blue_moon() {return true;}

  //SHTe ni triabva i funktsiia koiato v
redki sluchai generira 
  //izklyuchenie. Nie si padame po
redkite sluchai i zatova
  //shte ia napravim vinagi da
generira izklyuchenie:
 void may_throw_exception()
 {
          std::cout << "Throwing an
exception...\n";
          throw
std::string("exception");
 }

  /*   Dotuk s podgotovkata.
Zapochvame po sushtestvo,
 *
 *   Edna promenliva v C++ mozhe da se razpolozhi v edno
 * ot slednite "mesta":
 *     - v registrite na protsesora
 *     - v statichnata pamet
 *     - v steka
 *     - v dinamichno zadelena pamet
 *
 *   Programistut pochti niama vuzmozhnosti da upravliava
 * polzvaneto na registrite v C++ zatova tozi metod
 * shte go ostavim na mira. Tam greshki ne mogat da
 * se dopuskat.
 *
 *   Razpolaganeto na obekti v statichnata pamet se
 * izvurshva predi izvikvaneto na funktsiiata main().
 * Sushtite obekti se razrushavat sled priklyuchvaneto
 * na main(). Programistut niama kontrol vurhu
 * upravlenieto na statichnata pamet, sledovatelno i
 * tam greshki ne mogat da se dopuskat. Eto primer na
 * polzvane na statichna promenliva: */
  my_class static_class("static
sample");

  /*   Promenlivite i obektite
razpolozheni v steka (izvestni
  * i kato lokalni promenlivi, kakto i kato "auto") se
suzdavat
 * v momenta na deklariraneto im a se razrushavat kogato
 * programata dostigne do kraia na lokalnata oblast (scope),
 * oboznachena sus zatvariashta kudrava skoba. Ponezhe
 * pametta se osvobozhdava avtomatichno, polzvaneto
 * na lokalni promenlivi ne vodi do utechki na pamet.
 * Vse pak tezi promenlivi si imat svoite ogranicheniia.
 * Primer: */
 void auto_example()
 {
         std::vector<my_class> vector_of_objects;
         std::vector<my_class *> vector_of_pointers;
          my_class object("auto
 object");              //*1
          object.use("as object");
                    //*2
          use_by_reference(object);                    //*3
          use_by_pointer(&object);                    
//*4
          vector_of_objects.push_back(object);         //*5
          vector_of_pointers.push_back(&object);      
//*6
          for (int index = 2; index < 4;
++index) {
                 std::ostringstream oss;
                  oss << "auto
" << index;
                 my_class inner(oss.str());
                  vector_of_objects.push_back(inner);     
//*5, *7
                  vector_of_pointers.push_back(&inner);  
 //*6
         }//*8
         //9
          vector_of_objects[0].use("as
the first object in the vector");
          vector_of_objects[2].use("as
the last object in the vector");
          vector_of_pointers[0]->use("as the first pointer in the vector");
          //vector_of_pointers[1]->use(""); -
bi bilo greshka!
 }

 /*Nablyudeniia:
 * 1, 2, 3, 4 lokalnite promenlivi sa lesni za upotreba
  * 5 Mozhe bi si mislim che postaviame obekta object v
konteinera
 *    Istinata e che kompilatorut suzdava kopie na object i
 *    postavia kopieto v konteinera. Pri slozhni obekti
 *    suzdavaneto na kopie mozhe da e dosta bavna operatsiia
 * 6 Mozhem da polzvame vektor ot ukazateli - togava niama
 *    kopirane na obekti. No i tova ne vinagi e udachno.
 * 7 std::vector ima nepriiatnoto svoistvo ot vreme na
 *   vreme da si promenia razmera, pri koeto zadelia nova
 *   pamet, kopira vsichki obekti v neia i razrushava
 *   obektite koito purvonachalno e sudurzhal. Pri goliam
 *   vektor sudurzhasht slozhni obekti tova mozhe da otneme
 *   neochakvano mnogo vreme!
 * 8 Pri dostigane na kraia na lokalnata oblast vsichki obekti
 *   suzdadeni v neia se razrushavat. V tozi moment
 *   vector_of_pointers sudurzha ukazateli kum veche
 *   razrusheni obekti!
 * 9 Sled kraia na vutreshniia tsikul kopiiata na obekta inner
 *   vse oshte sa dostupni za upotreba
 * 10 (ne demonstrirano) poniakoga ima ogranichenie na razmera
 *   na steka koito e dostupen za programite. Naprimer
 *   sobstvenicheskite draiveri na NVidia ne vurviat na
 *   kernel s 4 KB stek - iavno programistite na NVidia sa
 *   se pouvlekli v polzvaneto na lokalni promenlivi.
 *
 *   Za da se reshat goreposochenite problemi se izpolzva
 * dinamichno zadeliane na pamet kogato e neobhodima. Tova
 * nalaga suotvetno osvobozhdavana kogato pametta ne e
 * neobhodima. Primer: */

 void dynamic_example()
 {
          my_class * pointer(new my_class("dynamically allocated"));
         std::vector<my_class *> vector_of_pointers;
         vector_of_pointers.push_back(pointer);
          pointer->use("as
pointer");
         use_by_reference(*pointer);
         use_by_pointer(pointer);
          vector_of_pointers[0]->use("as the first pointer in the vector");
         delete pointer;
 }

 /*
  *   Obektite suzdadeni s new se razpolagat v dinamichnata
pamet.
  * Te ostavat i sled kraia na lokalnata oblast (skope).
Postaviane
  * na ukazateli kum tezi obekti v konteineri e znachitelno
po-burz
  * protses. Razrushavaneto na tezi obekti e zadulzhenie na
programista
 * i primer za takova razrushavane e posledniia red.
  *   Kogato po edna ili druga prichina operatorut delete ne
se
  * izpulni za taka suzdaden obekt se poluchava utechka na
pamet.
 * Primeri: */
 void simple_leak()
 {
          my_class * pointer(new my_class("*simple leak"));
 }

 void another_simple_leak()
 {
          my_class * pointer(new my_class("*another simple leak"));
          pointer = new
my_class("another object...");
          //sled gorniia red veche e
nevuzmozhno da se osvobodi pametta 
          //zadelena za obekt
"*another simple leak"
         delete pointer;
 }

 void conditional_leak()
 {
          my_class * pointer(new my_class("*conditional leak"));
         //100 reda kod
         if (is_blue_moon())
         return;
         //oshte 100 reda kod
         delete pointer;
 }

 void leak_on_exception()
 {
          my_class * pointer(new my_class("*leak on exception"));
         may_throw_exception();
         delete pointer;
 }

 /*
  *   Kakto e vidno ot rezultata ot programata, gornite 4
obekta
  * se suzdavat no nikoga ne se razrushavat. Pametta zaeta ot
tiah
 * ostava neizpolzvaema za drugi tseli do priklyuchvane na
  * programata. Ako edna takava funktsiia se izpulniava v tsikul
to
 * za kratko vreme tsialata pamet na sistemata (v ramkite na
 * limitite - ako ima takiva) shte bude neizpolzvaema i tova
 * riadko e hubavo neshto.
 *
  *   Niakoi programisti na C++ vse oshte polzvat
malloc()/free()
 * za upravlenie na pametta. Niama da davam primeri s tezi
  * funktsii zashtoto (1) te sa arhaichen ostatuk ot C, (2) mozhe
da
  * se pishe C++ bez vuobshte da se polzvat tezi funktsii i (3)
vseki
 * programist na C++ koito produlzhava da gi polzva zasluzhava
 * lek elektroshok.
 *
 *   I taka stigame do sushtnostta na statiiata.
 *
 *   Purviiat ot modernite metodi za upravlenie na pametta
 * e std::auto_ptr. Polzvaiki go mozhem da izbegnem
 * goreopisanite utechki, zashtoto pri izlizaneto ot lokalnata
 * oblast auto_ptr garantirano unishtozhava obekta koito e
 * bil suzdaden: */
 void simple_autoptr()
 {
          std::auto_ptr<my_class> pointer(new my_class("simple auto_ptr"));
          //primeri za upotreba na
obekti kontrolirani s auto_ptr:
          pointer->use("as
pointer");
         use_by_pointer(pointer.get());
         use_by_reference(*pointer);
 }

 void conditional_autoptr()
 {
          std::auto_ptr<my_class> pointer(new my_class("conditional auto_ptr"));
         if (is_blue_moon())
         return;
          // auto_ptr ne se nuzhdae
ot "delete pointer;"
          // no ako ima nuzhda
programistut mozhe da osvobodi pametta 
         // predvaritelno:
          pointer.reset(); // tova
ne se izpulniava
 }

  void
autoptr_and_exception()
 {
          std::auto_ptr<my_class> pointer(new my_class("auto_ptr and exception"));
         may_throw_exception();
 }

 /*
  *   Zabelezhete che vsichki obekti suzdadeni s auto_ptr sa
nadlezhno razrusheni.
  * Po-podrobna statiia za polzvane na auto_ptr (na angliiski)
ima na:
  * //http://www.gotw.ca/publications/using_auto_ptr_effectively.htm
 *
  *   auto_ptr vurshi dobra rabota kogato iskame da postavim
obektite
  * v dinamichnata pamet vmesto v steka, no si ima i svoite
nedostatutsi.
  * Nai-seriozniiat ot tiah e che auto_ptr ukazateli ne mogat da
se
 * slagat v STL konteineri.
 *
  *   boost::shared_ptr e edin po-umen avtomatichen ukazatel.
Toi
  * pomni kolko puti e kopiran i kogato broiachut na kopiiata
stane
 * 0 obektut se samoiztriva. boost::shared_ptr obekti mogat
  * da se postaviat v konteineri. Te mogat da ostanat da
sushtestvuvat
  * sled kraia na lokalnata oblast v sluchai che sa nuzhni
drugade.
 *   Primer: */

 void shared_ptr_demo()
 {
          typedef
 boost::shared_ptr<my_class> sp_my_class;     //*1
         std::vector<sp_my_class> vector;
          sp_my_class example1(new my_class("the first shared_ptr object"));
          example1->use("as
pointer");
         use_by_pointer(example1.get());
         use_by_reference(*example1);
          vector.push_back(example1);                        
 //*2
          example1.reset();                                  
 //*3
          for (int index = 2; index < 4;
++index) {
                 std::ostringstream oss;
                  oss << "shared_ptr " << index;
                  sp_my_class inner(new my_class(oss.str()));
                  vector.push_back(inner);                   
     //*2
         }
          vector[0]->use("as
vector[0]");
          vector[1]->use("as
 vector[1]");                      //*4
          sp_my_class example2(new my_class("another shared_ptr object"));
          example2 = vector[2];                              
 //*5
         may_throw_exception();
  }                                                       
//*6

 /*
 *   Komentari:
 * 1 CHesto e udobno vednaga sled definitsiiata na klasa da se
 *   definira i shared_ptr kum sushtiia klas
  * 2 Postaviane na obekti kontrolirani s shared_ptr v
konteineri
 *   ne vodi do kopirane na obektite kakuvto beshe sluchaia s
 *   auto obektite po-gore
  * 3 Ako durzhim da obiavim che example1 veche ne sochi kum obekt
mozhe
  *   da polzvame reset(). Ako niama druga referentsiia kum
obekta
  *   toi shte bude unishtozhen, no v nashiia sluchai obektut e
slozhen v
  *   konteiner i shte produlzhi da zaema pamet dokato ima nuzhda
ot
 *   nego, t.e. dokato konteinerut ne bude razrushen.
 * 4 shared_ptr obektite ostanaha aktivni i sled kraia na
 *   lokalnata oblast
 * 5 Na shared_ptr ukazateli mogat da se prisvoiavat drugi
 *   stoinosti bez tova da vodi do utechki na pamet.
 * 6 Pri izlizane ot funktsiiata vsichki obekti se unishtozhavat
 *   zashtoto ot tiah niama poveche nuzhda. Dori i generiranoto
 *   izklyuchenie ne mozhe da zabludi shared_ptr.
 *
 *   shared_ptr obektite imat i niakolko osobenosti s koito
 * triabva da se suobraziavame:
 * 1. Nedeite da suzdavate tsirkuliarni verigi. Primer:
 *   - Obekt A sudurzha shared_ptr kum sebe si
 *   - Obekt A sudurzha shared_ptr kum obekt B i obekt B
 *     sudurzha shared_ptr kum obekt A
 *   - Obekt A sudurzha shared_ptr kum obekt B i obekt B
 *     sudurzha shared_ptr kum obekt V, ... obekt U
 *     sudurzha shared_ptr kum obekt A
 *   Resheniia: Polzvaite STL konteineri ili boost::weak_ptr.
 * 2. Nedeite da izpolzvate vremenni shared_ptr obekti
 *   kato parametri na funktsii a vinagi suzdavaite
 *   imenovani shared_ptr obekti. Primer (ot dokumentatsiiata
 *   na boost):
 void f(shared_ptr, int){}
 int g(){}

 void ok()
 {
 shared_ptr p(new int(2));
 f(p, g());
 }

 void bad()
 {
 f(shared_ptr(new int(2)), g());
 }
 *   Tui kato porednostta na izchisliavane na argumentite
 * na funktsiiata e neopredelen, vuzmozhno e purvo da se
 * izvika g(), tia da generira izklyuchenie oshte predi
 * konstruktora na shared_ptr obekta da e bil izvikan.
 * Az lichno si imah razpravii s edin kompilator koito
 * v debug rezhim suzdava kod koito izchisliava parametrite
 * po edin nachin, a v normalen rezhim - po drug. Programata
 * vurveshe idealno v debugera mi no kato se kompilira
 * kato za pred klient se durzheshe mnogo zle.
 *
 *   V zaklyuchenie: Ako pishete programi koito:
 *     - rabotiat s goliam broi obekti
 *     - razpolagat tezi obekti v konteineri
 *     - ne triabva da imat utechki na pamet
 *     - triabva da imat prilichno burzodeistvie
 *  bih Vi preporuchal da upravliavate sus shared_ptr vseki
 *  obekt po-goliam ot desetina baita. Suobraziavaite se
 *  sus osobenostite na shared_ptr i muchitelnoto tursene
 *  na utechki na pamet ostava v istoriiata.
 *
 *  Eto i glavnata programa: */
 int main()
 {
          std::cout << "program
started.\n";
         auto_example();
         dynamic_example();
         simple_leak();
         another_simple_leak();
         conditional_leak();
         try {
                 leak_on_exception();
          } catch (const std::string exception) {
                  std::cout << "caught exception\n";
         }
         simple_autoptr();
         conditional_autoptr();
         try {
                 autoptr_and_exception();
          } catch (const std::string exception) {
                  std::cout << "caught second exception\n";
         }
         try {
                 shared_ptr_demo();
          } catch (const std::string exception) {
                  std::cout << "caught third exception\n";
         }

          std::cout << "program
ended.\n";
         return 0;
 }

 /* Rezultat ot izpulnenieto:

 creating 'static sample'
 program started.
 creating 'auto object'
 Using 'auto object': as object
 Using 'auto object': from function use_by_reference()
 Using 'auto object': from function use_by_pointer()
 creating 'copy of auto object'
 creating 'auto 2'
 creating 'copy of copy of auto object'
 creating 'copy of auto 2'
 deleting 'copy of auto object'
 deleting 'auto 2'
 creating 'auto 3'
 creating 'copy of copy of copy of auto object'
 creating 'copy of copy of auto 2'
 creating 'copy of auto 3'
 deleting 'copy of copy of auto object'
 deleting 'copy of auto 2'
 deleting 'auto 3'
  Using 'copy of copy of copy of auto object': as the first
object in the vector
 Using 'copy of auto 3': as the last object in the vector
 Using 'auto object': as the first pointer in the vector
 deleting 'auto object'
 deleting 'copy of copy of copy of auto object'
 deleting 'copy of copy of auto 2'
 deleting 'copy of auto 3'
 creating 'dynamically allocated'
 Using 'dynamically allocated': as pointer
  Using 'dynamically allocated': from function
use_by_reference()
  Using 'dynamically allocated': from function
use_by_pointer()
  Using 'dynamically allocated': as the first pointer in the
vector
 deleting 'dynamically allocated'
 creating '*simple leak'
 creating '*another simple leak'
 creating 'another object...'
 deleting 'another object...'
 creating '*conditional leak'
 creating '*leak on exception'
 Throwing an exception...
 caught exception
 creating 'simple auto_ptr'
 Using 'simple auto_ptr': as pointer
 Using 'simple auto_ptr': from function use_by_pointer()
 Using 'simple auto_ptr': from function use_by_reference()
 deleting 'simple auto_ptr'
 creating 'conditional auto_ptr'
 deleting 'conditional auto_ptr'
 creating 'auto_ptr and exception'
 Throwing an exception...
 deleting 'auto_ptr and exception'
 caught second exception
 creating 'the first shared_ptr object'
 Using 'the first shared_ptr object': as pointer
  Using 'the first shared_ptr object': from function
use_by_pointer()
  Using 'the first shared_ptr object': from function
use_by_reference()
 creating 'shared_ptr 2'
 creating 'shared_ptr 3'
 Using 'the first shared_ptr object': as vector[0]
 Using 'shared_ptr 2': as vector[1]
 creating 'another shared_ptr object'
 deleting 'another shared_ptr object'
 Throwing an exception...
 deleting 'the first shared_ptr object'
 deleting 'shared_ptr 2'
 deleting 'shared_ptr 3'
 caught third exception
 program ended.
 deleting 'static sample'
 */

P.S. Po niakakva prichina v rezhim "pregled" statiiata izglezhdashe dobre, a sled publikuvaneto niakoi redove se preformatiraha.
Originalniiat tekst e go ima na:
http://home.exetel.com.au/v/test1.cpp
Kirilitsata e na utf8.
Molia ueb-mastura da opravi protsesa na publikuvane - ako vuobshte e vuzmozhno.

P.P.S Statiiata izglezhda dobre vuv "Variant za otpechatvane"


<< Programirane pod Linuks. Vuvedenie za nachinaeshti. | T2 Project ima nuzhda ot pomosht >>