[C++] kopiuj przy zapisie (zamianie)

0

Cześć, mam problem ze zrozumieniem kodu, mógłby mi ktoś wyjaśnić mniej więcej o co w tym chodzi? Większości nie rozumiem.
tstring.h:

#ifndef TSTRING_H
#define TSTRING_H

class TString
{
class StrContainer
{
public:
    StrContainer() : str(0), length(0), count(1) {}
    ~StrContainer() { if (str) delete [] str; }
    char* str;
    unsigned length;
    unsigned count;
} *strPtr;

static int objnum;
void print(const char* msg=0) const;

public:
    TString(const char* s=0);
    TString(const TString& s);
    ~TString();
    TString& operator=(const TString& s);
    void toupper();
};

#endif // TSTRING_H

tstring.cc:

#include "tstring.h"
#include

using namespace std;

int TString::objnum = 0;

TString::TString(const char* s)
{
    strPtr = new StrContainer;
    if (s!=0)
    {
        strPtr->length = strlen(s);
        strPtr->str = new char[strPtr->length + 1];
        strcpy(strPtr->str, s);
    }

    ++objnum;
    #ifdef DEBUG
    print("c-tor");
    #endif
}

TString::~TString()
{
    --objnum;
    if (--strPtr->count == 0)
    {   // tutaj print żeby zobaczyć zawartość jeszcze przed usunięciem
        #ifdef DEBUG
        print("d-tor");
        #endif
        delete strPtr;
    }
}

TString::TString(const TString& s)
{
    ++s.strPtr->count;
    strPtr = s.strPtr;
    ++objnum;
    #ifdef DEBUG
    print("cc-tor");
    #endif
}

TString& TString::operator=(const TString& s)
{
    if (this == &s) return *this;
    if (--strPtr->count == 0)
    {
        delete strPtr;
    }
    ++s.strPtr->count;
    strPtr = s.strPtr;
    #ifdef DEBUG
    print("operator=");
    #endif
    return *this;
}

void TString::print(const char* msg) const
{
    cout << "[";
    cout.fill('0');
    cout.width(2);
    cout << strPtr->count;
    cout << "/";
    cout.width(2);
    cout << objnum << "] ";
    cout.fill(' ');
    cout.width(12);
    cout << ((msg!=0)?msg:"-") << " [";
    cout.width(25);
    cout << ((strPtr->str!=0)?strPtr->str:"-") << "]" << endl;
}

void TString::toupper()
{
    char *p;
    unsigned len = strPtr->length;
    if (strPtr->count > 1)
    {
        p = new char[ len + 1 ];
        strcpy( p, strPtr->str );
        --strPtr->count;
        strPtr = new StrContainer;
        strPtr->length = len;
        strPtr->str = p;
    }
    // teraz powiększamy litery
    for (unsigned i = 0; i < len; ++i)
    {
        strPtr->str[i] = std::toupper( strPtr->str[i] );
    }
}

main.cc:

#include "tstring.h"

using namespace std;

int main()
{
    TString a;
    TString a2("obiekt drugi");
    TString a3(a2);
    TString a4 = a = a2;
    a.toupper();
}
0

idea copy-on-write jest taka:

kopiowanie obiektow nie powoduje skopiowania danych w nich zawartych (linijka a4=a=a2).
w momencie takiego kopiowania, obiekty zaczynaja wspoldzielic te same dane. to znaczy, ze po tej linijce, a4 a2 i a beda zawierac odniesienia do TEJ SAMEJ tablicy znakow, nie do trzech takich samych.

w momencie gdy ktorys z obiektow postanowi zmienic cos w swojej zawartosci (linijka a.toupper) - jesli jego dane sa wspoldzielone - musi nastapic ODERWANIE GO od wspoldzielonych tresci.

jesli obiekt nie oderwalby sie i dokonal zmiany, zmiana defacto dokonalaby sie u wszystkich obiektow wspoldzielacych dane - gdyz te dane byly tylko jedne..

obiekt A musi wiec sie oderwac od wspoldzielenia, czyli dokonac KOPII DANYCH wspoldzielonych i zapamietac te kopie jako swoja wlasnosc, i dopiero wowczas bedzie mogl dokonac zapisu do tych danych (czyli np. podmienic literki na duze).

stad nazwa: COPY ON WRITE: kopiuj dane dopiero wtedy, gdy chcesz je zmodyfikowac

a teraz majac to glowie, popatrz na:

  • klase strcontainer: to sa te wlasciwe dane trzymane przez TString. poza byciem tablica znakow, sa one swiadome wspoldzielenia i wiedza ile TStringow z nich korzysta aktualnie

  • konstruktor TString/StrContainer - zobacz jak ustawiaja liczniki

  • destruktor TString - zobacz co robi z licznikiem i kiedy faktycznie usuwa dane

  • konstrutor kopiujacy TString oraz operator= TString - zobacz, co one tak naprawde w ogole robia

  • metode toupper TStringa - zobacz jak reaguje na licznik i co wtedy robi PRZED modyfikacja danych

1 użytkowników online, w tym zalogowanych: 0, gości: 1