mesajflaviu wrote:[...]
P.S. Parca aud oale si strachini sparte

"Bang, dong, zang!..". Nu va speriati, e un botez la chiezii de la zece.
Ok, sa incercam sa lamurim chestia cu
reference count.
Sa zicem ca am urmat un curs finantat din fonduri UE, numit "C++ pentru profesorii de C cu cin si cout".
Pentru verificarea cunostintelor si certificare, ni se cere sa implementam clasa String.
Deci, la treaba!
Code: Select all
class String
{
char* m_pBuffer;
public:
String();
String(const char* p);
String(const String& r);
// ... s.a.m.d.
~String();
};
Code: Select all
String::String() : m_pBuffer(0)
{
}
String::String(const char* p)
{
m_pBuffer = new char[strlen(p) + 1];
strcpy(m_pBuffer, p);
}
String::String(const String& r)
{
if(r.m_pBuffer == 0)
{
m_pBuffer = 0;
}
else
{
m_pBuffer = new char[strlen(r.m_pBuffer) + 1];
strcpy(m_pBuffer, r.m_pBuffer);
}
}
String::~String()
{
delete []m_pBuffer;
}
Merje? Mai sunt cateva mici corecturi de facut, insa in principiu, merge. Se poate si mai bine? De ce, cum?
Pai, daca scriu asa...
Code: Select all
void DoSomethingCool()
{
String s1 = "Un text lung cat zidu' chinezesc...";
String s2 = s1;
String s3 = s2;
// s.a.m.d.
}
int main()
{
DoSomethingCool();
return 0;
}
...se poate observa ca
s1,
s2 si
s3 "contin" toate "Un text lung cat zidu' chinezesc...".
Ceea ce si trebuie. Insa daca ne uitam si mai atent pointerul
m_pBuffer, observam arata catre adrese diferite.
Deci (si asta se poate observa si din cod), s-au alocat trei zone de memorie pentru exact acelasi text.
Curata risipa mai ales ca stringurile sunt intensiv folosite intr-o aplicatie serioasa, iar asemenea copii pot aparea destul de des.
Este ca si cum am cheltui toti banii dati de UE pentru 100 km de autostrada ca sa facem doar un kilometru. Deja vu?
Aici apare ideea de
reference counting.
Cam asa:
Code: Select all
class String
{
public:
char* m_pBuffer;
mutable int m_nRefs; // reference count
public:
String();
String(const char* p);
String(const String& r);
// ... s.a.m.d.
~String();
};
Code: Select all
String::String() : m_pBuffer(0), m_nRefs(0)
{
}
String::String(const char* p) : m_pBuffer(0), m_nRefs(0)
{
if(p != 0)
{
m_pBuffer = new char[strlen(p) + 1];
strcpy(m_pBuffer, p);
}
}
String::String(const String& r)
{
m_pBuffer = r.m_pBuffer;
m_nRefs = ++r.m_nRefs;
}
String::~String()
{
if(--m_nRefs < 1)
delete []m_pBuffer;
}
Se observa cu ochiul liber ca in constructorul de copiere nu am mai alocat o zona noua de memorie in care sa copii.
Am copiat pur si simplu pointerul
m_pBuffer, care arata catre adresa care contine textul.
Ca sa stiu cate obiecte String arata catre aceeasi zona de memorie, am adaugat o variabila "reference counter",
m_nRefs.
De fiecare data cand fac o copiere de genul asta, incrementez
m_nRefs.
Pe destructor, decrementez
m_nRefs apoi vad ce valoare are.
Daca m_nRefs > 0, inseamna ca mai exista si alte obiecte care folosesc (care se
refera la) aceeasi zona punctata (
referita) de
m_pBuffer deci il las in pace.
Daca m_nRefs ajunge la zero, inseamna ca asta-i ultimul obiect care o mai foloseste (se
refera la ea) asa ca eliberez
m_pBuffer.
Am subliniat "refera" si "referita" pentru a arata de unde provine denumirea de "reference count" si ca nu are legatura cu tipul referinta (reference) din C++.
Simplu. In MFC CString, e putin altfel insa ideea e aceeasi.