c++ memory leak - zarządzanie pamięcią

1

Na forum jest wiele wątków w których można przeczytać żeby "w c++ nie używać new / delete" używaj std::vector
Będąc przekorny napisałem sobie klasę do zarządzania pamięcią.
Proszę o sprawdzenie mojego programu, czy w nim zachodzą wycieki pamięci, czy jednak jest pozbawiony wycieku pamięci. W funkcjach "add_line" i "delete_line" tworze tymczasowa tablice o nazwie "tmp_table" i moje pytanie brzmi "Czy destruktor czyści tą zarezerwowaną pamięć?"
Jeżeli są jakieś uwagi dotyczące samej budowy klasy to też o nie poproszę.

aha jeszcze jedna uwaga przy tworzeniu tablicy nie wprowadzajcie dużych wartości ponieważ będzie trzeba tą tablicę wypełnić, poniżej wskazówka
można lub nie to zrobić przy metodach "fill_tab()" i "add_line"

//tmp_table[pos][j] = 0;
//tmp_table[pos][j] = (rand() % 100) + 1; //<-- usun komentarz
cout << "Enter [" << pos << "][" << j << "] value : "; //<-- postaw komentarz
cin >> tmp_table[pos][j]; //<-- postaw komentarz

Listing 1.

//2022 Copyright (©) by nanomrowka20
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <limits> 
#include <cmath>
#include <vector>

using namespace std;

class newSpace
{
private:
    int ** tab;
    int ** tmp_table;
    int rowCount;   //ilosc wierszy
    int colCount;   //ilosc kolumn
    int pos;        //pozycja
public:
    newSpace()
    {
        cout<<"Konstruktor domyslnny bezparametrowy"<<'\n';
        //int ** tab = new int*[1]{0}; //Core Dump - Segmentation fault
        this->tab = new int*[1]{0};
        for(unsigned int i = 0; i < 1; ++i)
            tab[i] = new int [1]{0};

        this->rowCount = 0;
        this->colCount = 0;
    }
    newSpace(int rowCount, int colCount)
    {
        if( (rowCount>0) && (colCount>0) )
        {
            cout<<"Konstruktor domyslnny"<<'\n';
            this->tab = new int*[rowCount]{0};
            for(int i = 0; i < rowCount; ++i)
                tab[i] = new int [colCount]{0};
        }
        this->rowCount = rowCount;
        this->colCount = colCount;
    }
    void create(int rowCount, int colCount)
    {
        if( (rowCount>0) && (colCount>0) )
        {
            cout<<"Konstruktor domyslnny"<<'\n';
            this->tab = new int*[rowCount]{0};
            for(int i = 0; i < rowCount; ++i)
                tab[i] = new int [colCount]{0};
        }
        this->rowCount = rowCount;
        this->colCount = colCount;
    }
    int add_line(int pos)
    {
        int iW = rowCount;
        int iK = colCount;
        //tworzymy nowa tablice o 1 wiersz wieksza
        int newSize = iW + 1;
        this->tmp_table = new int*[newSize];
        for(int i = 0; i < newSize; ++i)
            tmp_table[i] = new int [iK];

        for(int i = 0, k = 0; i < newSize; ++i)
        {
            if(i == pos)
            {
                //cout << "\n";
                for(int j = 0, s = 0; j < iK; ++j, ++s)
                {
                    //tmp_table[pos][j] = 0;
                    //tmp_table[pos][j] = (rand() % 100) + 1;
                    cout << "Enter [" << pos << "][" << j << "] value : ";
                    cin >> tmp_table[pos][j];
                    //cout << "tmp_table["<<pos<<"]["<<j<<"] " << tmp_table[pos][j] << "\n";
                }
            }
            else
            {
                //cout << "\n";
                for(int j = 0, m = i; j < iK; ++j)
                {
                    tmp_table[m][j] = tab[k][j];
                    //cout << "tmp_table["<<m<<"]["<<j<<"] " << tmp_table[m][j] << " tab["<<k<<"]["<<j<<"] "<< tab[k][j] << "\n";
                }
                ++k;
            }
        }
        rowCount = newSize;
        tab = tmp_table;
        return this->rowCount;
    }
    int delete_line(int pos)
    {
        int iW = rowCount;
        int iK = colCount;
        //tworzymy nowa tablice o 1 wiersz mniejsza
        int newSize = iW - 1;

        int ** tmp_table = new int*[newSize];
        for(int i = 0; i < newSize; ++i)
            tmp_table[i] = new int [iK];

        for(int i = 0, k = 0; i < newSize; ++i)
        {
            if(i == pos)
            {
                ++k;
                cout << "\n";
                for(int j = 0; j < iK; ++j)
                {
                    tmp_table[pos][j] = tab[k][j];
                    //cout << "tmp_table["<<pos<<"]["<<j<<"] " << tmp_table[pos][j] << "\ttab["<<k<<"]["<<j<<"] "<< tab[k][j] << "\n";
                }
                ++k;
            }
            else
            {
                //cout << "\n";
                for(int j = 0; j < iK; ++j)
                {
                    tmp_table[i][j] = tab[k][j];
                    //cout << "tmp_table["<<i<<"]["<<j<<"] " << tmp_table[i][j] << "\ttab["<<k<<"]["<<j<<"] "<< tab[k][j] << "\n";
                }
                ++k;
            }
        }
        rowCount = newSize;
        tab = tmp_table;
        return this->rowCount;
    }
    int size_rowCount()
    {
        return this->rowCount;
    }
    int size_colCount()
    {
        return this->colCount;
    }
    ~newSpace()
    {
        //Don't forget to delete the array of pointers
        for(int i = 0; i < rowCount; ++i)
            delete [] tab[i];
        delete [] tab;
        cout<<"~Destructor"<<'\n';
    };
    void fill_tab()
    {
        for(int i = 0; i < rowCount; ++i)
        {
            for(int j = 0; j < colCount; ++j)
            {
                //tab[i][j] = (rand() % 100) + 1;
                cout << "Enter [" << i << "][" << j << "] value : ";
                cin >> tab[i][j];
            }
            cout << endl;
        }

    }
    void show_me()
    {
        cout << "\n";
        for(int i = 0; i < rowCount; ++i)
        {
            cout << "Pole position " << i << setw(4) << std::setfill(' ') << right << "\t";
            for(int j = 0; j < colCount; ++j)
            {
                cout << setw(4) << std::setfill(' ') << right << tab[i][j] << " ";
            }
            cout << "\n";
        }
        cout << "\n";
    }
};

typedef struct
{
    int id;
    string description;
} Operation;

int check_input();
void clear_input();
int menu();

int main()
{
    srand(time(NULL));
    int iW{0}, iK{0}; //iW - ilosc wierszy, iK - ilosc kolumn
    int pos{0};
    newSpace tab;

    bool infinity = true;
    for(;infinity;)
    {
        int currentSize = tab.size_rowCount();
        int r = menu();
        cout << "Select an action : ";
        int choice { check_input() };
        switch( choice )
        {
        case 1:
            while((cout<<"Ile wierszy : ")&&(cin>>iW)&&(cout<<"Ile kolumn : ")&&(cin>>iK))
            {
                tab.create(iW,iK);break;
            }
            break;

        case 2:
            if( currentSize == 0 )
            {
                cout << "\n\t\"the array is empty\"\n" << "\n";
                break;
            } else {
                tab.fill_tab();
            }
            break;

        case 3:
            if( currentSize == 0 )
            {
                cout << "\n\t\"the array is empty\"\n" << "\n";
                break;
            } else {
                tab.show_me();
            }
            break;

        case 4:
            if( currentSize == 0 )
            {
                cout << "\n\t\"the array is empty\"\n" << "\n";
                break;
            } else {
                while( (cout << "\nWstaw wiersz na pozycji z zakresu ( " << 0 << " - " << currentSize << " ) : " ) && (!( cin >> pos ) ||( pos < 0 ) ||( pos > currentSize ) ) )
                {
                    clear_input();
                    continue;
                }
                tab.add_line(pos);
            }
            break;

        case 5:
            if( currentSize == 0 )
            {
                cout << "\n\t\"the array is empty\"\n" << "\n";
                break;
            } else {
                while( (cout << "\nUsun wiersz na pozycji z zakresu ( " << 0 << " - " << currentSize-1 << " ) : " ) && (!( cin >> pos ) ||( pos < 0 ) ||( pos > currentSize-1 ) ) )
                {
                    clear_input();
                    continue;
                }
                tab.delete_line(pos);
            }
            break;

        case 6:
            cout << "\n\t\t\tKoniec programu. Bye!\n";
            infinity = false;
            break;

        default:
            cout << "\tMozesz wybrac tylko od 1 do " << r << "\n\n";
            break;
        }
    }

    return 0;
}
int check_input()
{
    int x;
    //while (!(cin >> x))
    //while (!(cin >> x) || x == 0 )
    while (!(cin >> x) || x == 0 || x < 0 )
    {
        if (cin.fail())
        {
            cout << "\tWprowadzony znak nie jest cyfra/liczba" << endl;
            cout << "\tProsze podac cyfre/liczbe : ";
            //czyscimy strumien wejsciowy std::cin
            clear_input();
            continue;
        }
        else if( x < 0 )
        {
            cout << "\tCyfra/Liczba " << x << " jest liczba ujemna" << endl;
            cout << "\tProsze podac cyfre/liczbe dosatnia : ";
            clear_input();
            continue;
        }
        else
        {
            cout << "\tNie moze byc " << x << endl;
            cout << "\tProsze podac cyfre/liczbe wieksza od ZERO : ";
            //czyscimy strumien wejsciowy std::cin
            clear_input();
            continue;
        }

    }
    return x;
}
void clear_input()
{
    cin.clear();
    cin.ignore( std::numeric_limits < std::streamsize >::max(), '\n' );
}
int menu()
{
    vector < Operation > data = {
        { 1, "Create table" },
        { 2, "Fill table" },
        { 3, "Print table" },
        { 4, "Add line" },
        { 5, "Delete Line" },
        { 6, "End the program" }
    };

    cout << "Menu : ";
    for(const auto & Item: data )
    {
        cout << "\t" << Item.id << " " << Item.description << endl;
    }
    int r = data.size();
    return r;
}


7
  1. Zdecydowanie brakuje konstruktora kopiującego: newSpace tab; { newSpace foo(tab); } masz wyciek nie zwolni się foo.tab oraz zonk tab.tab zwolniony dwukrotnie.
  2. Zdecydowanie brakuje operatora przypisania: newSpace tab,foo; tab=foo; masz wyciek oraz zonk.
  3. newSpace tab; tab.Create(2,2); masz wyciek, ponieważ Create nie zwalnia poprzedniej tab;
  4. Co robi int pos; w składowych klasy?
  5. Co robi int **tmp_table; w składowych klasy? Przecież się samo prosi o zmienną lokalną.
  6. Radzę użyć typu size_t dla rowCount oraz colCount;
  7. Radzę użyć int *data; oraz metody int &at(size_t r,size_t c) { return data[r*colCount+c]; } użycie: at(3,5)=666;
  8. Czemu nie używasz listy inicjalizacyjnej konstruktora?
  9. Czemu dla tablicy o rozmiarach 0,0/0,X/Y,0 nie użyć zwyczajnie tab=nullptr;?
  10. Czemu z menu nie pójdziesz ciut dalej: https://4programmers.net/Forum/C_i_C++/352675-stos_funkcje_zapisu_i_odczytu_pliku_binarnego?p=1772198#id1772198
6

https://dsp.krzaq.cc/post/176/ucze-sie-cxx-kiedy-uzywac-new-i-delete/
Dziel kod na mniejsze funkcje.
przydał by się przykład danych wejściowych.

https://godbolt.org/z/7TGxr8vEv

https://en.cppreference.com/w/cpp/language/rule_of_three

Poprawione przez użycie std::vector https://godbolt.org/z/b7ejYTsaY - bez zastanawiania się, więc jak coś nie działa jak oczekujesz to już sobie sam popraw.

5

-fsanitize=address ale nie sprawdzałem kodu

==22==ERROR: AddressSanitizer failed to allocate 0xdfff0001000 (15392894357504) bytes at address 2008fff7000 (errno: 12)
==22==ReserveShadowMemoryRange failed while trying to map 0xdfff0001000 bytes. Perhaps you're using ulimit -v
3

Na problemy zgłoszone przez @_13th_Dragon tu masz podkład teoetyczny
https://en.cppreference.com/w/cpp/language/rule_of_three

Co osobiście mam krytycznego ...
Drukowanie jako forma potwierdzenia wykonania
Drukowanie "konstruktor domyślny" gdy takim nie jest
Drukowanie na cout, jedyną metodę która ma powód drukować bym widział:

void show_me(std::ostream out)

Lub operator <<

W ogóle to takie bardzo C jest, mało C++ (aż się prosi użycie referencji, nie ma)
Brak jest accesora do konkretnej komórki (najlepiej w formie operatora [], choć & at() też ok). Po co macierz, gdzie nie ma dostepu do komórki ???
Rzeczywiście dziwne okodowanie przypadku rozmiar zero

2

tu sie samo nasuwa użycie malloc/free dla całej tablicy w jednej instrukcji zamiast tych wszystkich new

2
Miang napisał(a):

tu sie samo nasuwa użycie malloc/free dla całej tablicy w jednej instrukcji zamiast tych wszystkich new

  • std::vector jest lepszym rozwiązaniem niż mieszanie do tego API z C.
  • Zakładam, że myślisz o jednym bloku pamięci, ale to zależy od wymagań, a on ma funkcjonalność add_line
1

Dziękuję wszystkim i każdemu z osobna @_13th_Dragon @@MarekR22 @several @ZrobieDobrze @Miang (wierzę że nikt się nie obrazi za kolejność) za konstruktywne uwagi, zacznę je wdrażać i przyjdę za jakiś czas z naniesionymi poprawkami.
@MarekR22 nie wiem jak Ci się chciało przerabiać to na std::vector, ale dziękuję przyda mi się dobry wzór

1

1
nanomrówka20 napisał(a):

Na forum jest wiele wątków w których można przeczytać żeby "w c++ nie używać new / delete" używaj std::vector

Mimo ze uzycie vector jest poprawne, to ja zdecydowanie wole unique_ptr. Czytajac kod od razu widac ze ma sie do czynienia z blokiem pamieci a nie zbiorem elementow, potencjalnie o zmiennym rozmiarze. Poza tym gdyby sprobowac cos takiego skopiowac to kompilator grzecznie sie wydrze zeby sie nie wyglupiac. Niestety czasami przydaje sie rozmiar przydzielonej pamieci - vector ma wbudowane, unique_ptr nie. Ale prosta struktura zawierajaca unique_ptr + rozmiar rozwiazuje problem.

0

na początku chciałbym skupić się na klasie, ponieważ nie wiem czy nie będzie trzeba jej przerobić
dalej nie jestem w stanie usunąć tablic pomocniczych tmp w "add_line(int pos)" i "delete_line(int pos)" co pewnie skutkuje wyciekiem pamięci

#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <limits>
#include <cmath>
#include <vector>

using namespace std;

class newSpace
{
private:
    int ** tab;
    int rowCount, colCount;   //ilosc wierszy, ilosc kolumn

public:
    newSpace()
    {
        tab = nullptr;  // NULL;
        this->rowCount = 0;
        this->colCount = 0;
    }
    newSpace(int rowSize, int colSize): rowCount( rowSize ), colCount( colSize )
    {
        this->rowCount = rowCount;
        this->colCount = colCount;
        //create(rowCount, colCount);
    }
    ~newSpace()
    {
        //Don't forget to delete the array of pointers
        for(int i = 0; i < rowCount; ++i)
            delete [] tab[i];
        delete [] tab;
        cout<<"~Destructor"<<'\n';
    };
    void create(int rowCount, int colCount)
    {

        if( (rowCount>0) && (colCount>0) )
        {

            this->tab = new int*[rowCount]{0};
            for(int i = 0; i < rowCount; ++i)
                tab[i] = new int [colCount]{0};
        }
        this->rowCount = rowCount;
        this->colCount = colCount;
    }
    // Konstruktor kopiujacy
    newSpace(const newSpace &original)
    {
        rowCount = original.rowCount;
        colCount = original.colCount;
        for(int i = 0; i < original.rowCount; ++i)
        {
            for (int j = 0; j < original.colCount; ++j)
            {
                tab[i][j] = original.tab[i][j];
            }
        }
    }

    newSpace & operator=(const newSpace& original)
    {
        //checking that the matricies are the same size
        /*
        if (rowCount != original.rowCount || colCount != original.colCount)
        {
            cout << "Cannot copy matricies!" << endl;
            //returns tab
            return *this;
        }
        */
        if(this == &original) return *this;

        //copies all values of the newSpace class
        rowCount = original.rowCount;
        colCount = original.colCount;
        for (int i = 0; i < original.rowCount; ++i)
        {
            for (int j = 0; j < original.colCount; ++j)
            {
                tab[i][j] = original.tab[i][j];
            }
        }
        return *this;
    }


    int add_line(int pos)
    {
        int iW = rowCount;
        int iK = colCount;
        //tworzymy nowa tablice o 1 wiersz wieksza
        int newSize = iW + 1;

        int ** tmp_table = new int*[newSize];
        for(int i = 0; i < newSize; ++i)
            tmp_table[i] = new int [iK];



        for(int i = 0, k = 0; i < newSize; ++i)
        {
            if(i == pos)
            {
                for(int j = 0, s = 0; j < iK; ++j, ++s)
                {
                    //tmp_table[pos][j] = (rand() % 100) + 1;
                    cout << "Enter [" << pos << "][" << j << "] value : ";
                    cin >> tmp_table[pos][j];
                }
            }
            else
            {
                for(int j = 0, m = i; j < iK; ++j)
                {
                    tmp_table[m][j] = tab[k][j];
                }
                ++k;
            }
        }
        rowCount = newSize;
        tab = tmp_table;


        return this->rowCount;
    }
    int delete_line(int pos)
    {
        int iW = rowCount;
        int iK = colCount;
        //tworzymy nowa tablice o 1 wiersz mniejsza
        int newSize = iW - 1;

        int ** tmp_table = new int*[newSize];
        for(int i = 0; i < newSize; ++i)
            tmp_table[i] = new int [iK];

        for(int i = 0, k = 0; i < newSize; ++i)
        {
            if(i == pos)
            {
                ++k;
                cout << "\n";
                for(int j = 0; j < iK; ++j)
                {
                    tmp_table[pos][j] = tab[k][j];
                }
                ++k;
            }
            else
            {
                for(int j = 0; j < iK; ++j)
                {
                    tmp_table[i][j] = tab[k][j];
                }
                ++k;
            }
        }
        rowCount = newSize;
        tab = tmp_table;


        return this->rowCount;
    }
    int size_rowCount()
    {
        return this->rowCount;
    }
    int size_colCount()
    {
        return this->colCount;
    }

    void fill_tab()
    {
        for(int i = 0; i < rowCount; ++i)
        {
            for(int j = 0; j < colCount; ++j)
            {
                //tab[i][j] = (rand() % 100) + 1;
                cout << "Enter [" << i << "][" << j << "] value : ";
                cin >> tab[i][j];
            }
            cout << endl;
        }

    }

    friend std::ostream& operator<<(std::ostream& out, const newSpace & obj)
    {
        out << "\n";
        for(int i = 0; i < obj.rowCount; ++i)
        {
            out << "Pole position " << i << setw(4) << std::setfill(' ') << right << "\t";
            for(int j = 0; j < obj.colCount; ++j)
            {
                out << setw(4) << std::setfill(' ') << right << obj.tab[i][j] << " ";
            }
            out << "\n";
        }
        out << "\n";

        return out;
    }
    void show_me(std::ostream& os)
    {
        for(int i = 0; i < rowCount; ++i)
        {
            os << "Pole position " << i << setw(4) << std::setfill(' ') << right << "\t";
            for(int j = 0; j < colCount; ++j)
            {
                os << setw(4) << std::setfill(' ') << right << tab[i][j] << " ";
            }
            os << "\n";
        }

    }
};

typedef struct
{
    int id;
    string description;     //const char *text; // tekst menu
    void(*ptr)(newSpace,int);
}Operation;

int check_input();
void clear_input();


int main()
{
    srand(time(NULL));
    int iW{0}, iK{0}; //iW - ilosc wierszy, iK - ilosc kolumn
    int pos{0};

    bool infinity = true;
    for(;infinity;)
    {
        newSpace tab;
        while((cout<<"Ile wierszy : ")&&(cin>>iW)&&(cout<<"Ile kolumn : ")&&(cin>>iK))
        {
            tab.create(iW,iK);
            if(not cin){infinity = false; break;}
            clear_input();
            break;

        }
        if(not cin){infinity = false; break;}
        int currentSize = tab.size_rowCount();
        tab.show_me(cout);
        tab.fill_tab();
        tab.show_me(cout);
        while( (cout << "\nWstaw wiersz na pozycji z zakresu ( " << 0 << " - " << currentSize << " ) : " ) && (!( cin >> pos ) ||( pos < 0 ) ||( pos > currentSize ) ) )
        {
            clear_input();
            continue;
        }
        tab.add_line(pos);
        tab.show_me(cout);
        while( (cout << "\nUsun wiersz na pozycji z zakresu ( " << 0 << " - " << currentSize << " ) : " ) && (!( cin >> pos ) ||( pos < 0 ) ||( pos > currentSize ) ) )
        {
            clear_input();
            continue;
        }
        tab.delete_line(pos);
        tab.show_me(cout);

        }


    return 0;
}

int check_input()
{
    int x;
    //while (!(cin >> x))
    //while (!(cin >> x) || x == 0 )
    while (!(cin >> x) || x == 0 || x < 0 )
    {
        if (cin.fail())
        {
            cout << "\tWprowadzony znak nie jest cyfra/liczba" << endl;
            cout << "\tProsze podac cyfre/liczbe : ";
            //czyscimy strumien wejsciowy std::cin
            clear_input();
            continue;
        }
        else if( x < 0 )
        {
            cout << "\tCyfra/Liczba " << x << " jest liczba ujemna" << endl;
            cout << "\tProsze podac cyfre/liczbe dosatnia : ";
            clear_input();
            continue;
        }
        else
        {
            cout << "\tNie moze byc " << x << endl;
            cout << "\tProsze podac cyfre/liczbe wieksza od ZERO : ";
            //czyscimy strumien wejsciowy std::cin
            clear_input();
            continue;
        }

    }
    return x;
}
void clear_input()
{
    cin.clear();
    cin.ignore( std::numeric_limits < std::streamsize >::max(), '\n' );
}

1

tak tyko przejrzałem

  1. Użyj narzędzi jak vlagrind i adress-sanitaziter

dalej nie jestem w stanie usunąć tablic pomocniczych tmp w "add_line(int pos)" i "delete_line(int pos)" co pewnie skutkuje wyciekiem pamięci

Musisz sobie odpowiedzieć na ważne pytanie co się dzieje z adresami wskaźników?

  1. Alokujesz tablice tmp, czyli mamy nowe miejsce w pamięci. ok
  2. potem co robisz przypisujesz wskaźniki czy wartości z pamięci?
  3. Jak zmieniają się adresy w tmp? Może wypisz sobie je.
    załóżmy trywialny przykład
int* p1 = new int;
*p1=123;
int *p2 = new int;
*p2=423;
p2=p1;
// Co teraz jak wypiszemy adresy wskaźników?
delete p1;
delete p2;

Po kolei zastanów się jak zmieniały się adresy, wartości i co robią delety.

Tak przeglądnąłem kod to ty w pewnym stopniu chcesz zrobić.... własny wektor.

vector<vector<data_type>> vec;

Może lepiej weź się za implementację vectora? do tego szablony.

  1. Nazewnictwo. Powinno być rozsądne np. nie tab a data. Kolejno warto czasami wprowadzić jakieś nazewnictwo, w różnych projektach widziałem różne ale ja np. membery klas lubię oznaczać przedrostkiem m czyli np. T mData; wiem od razu co jest czym a u ciebie mamy tab, tmp_tab. Czasami używasz camel zmiennaMoja a czasami podkreslenia zmienna_moja.
  2. Warto pomyśleć o rozbijaniu dużych funkcji. w tej add_line masz np. dużego for, czy można by go przenieść do zewnętrznej funkcji a może coś innego? https://refactoring.com/catalog/
  3. Abstrahując od kodu wyżej nie wiem na ile znasz i może tez warto poczytać o:
  4. wzorcu RAII czy też allokatorach

Podsumowanie: Rozumiem to ćwiczenia, może warto napisać własny vector, unique_ptr, shared_ptr?
edit:
no i warto znać ten wzorzec
https://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom

1
nanomrówka20 napisał(a):

na początku chciałbym skupić się na klasie, ponieważ nie wiem czy nie będzie trzeba jej przerobić
dalej nie jestem w stanie usunąć tablic pomocniczych tmp w "add_line(int pos)" i "delete_line(int pos)" co pewnie skutkuje wyciekiem pamięci

    newSpace(int rowSize, int colSize): rowCount( rowSize ), colCount( colSize )
    {
        this->rowCount = rowCount;
        this->colCount = colCount;
        //create(rowCount, colCount);
    }

Parametry konstruktora warto nazywać tak samo jak składowe, dla łatwiejszego odczytu komunikatów o błędzie.
newSpace(int rowCount,int colCount):rowCount(rowCount),colCount(colCount) - zadziała poprawnie
this->rowCount = rowCount; - składową klasy nadpisujesz jej własną wrtością? WTF?
Zrób Create statyczną zwracającą wskaźnik int **create(int rowCount,int colCount) i nie zapomnij zwrócić nullptr jeżeli któryś z wymiarów zerowy, wtedy:
newSpace(int rowCount,int colCount):tab(create(rowCount,colCount)),rowCount(rowCount),colCount(colCount) {}

>     newSpace(const newSpace &original)
>     {
>         rowCount = original.rowCount;
>         colCount = original.colCount;
>         for(int i = 0; i < original.rowCount; ++i)
>         {
>             for (int j = 0; j < original.colCount; ++j)
>             {
>                 tab[i][j] = original.tab[i][j];
>             }
>         }
>     }

To też konstruktor, stwórz statyczną metodę int **copy(int **tab,int rowCount,int colCount)
Wtedy: newSpace(const newSpace &src):tab(copy(src.tab,src.rowCount,src.colCount),src.rowCount,src.colCount) {}

>     newSpace & operator=(const newSpace& original)
>     {
>         //checking that the matricies are the same size
>         /*
>         if (rowCount != original.rowCount || colCount != original.colCount)
>         {
>             cout << "Cannot copy matricies!" << endl;
>             //returns tab
>             return *this;
>         }
>         */
>         if(this == &original) return *this;
> 
>         //copies all values of the newSpace class
>         rowCount = original.rowCount;
>         colCount = original.colCount;
>         for (int i = 0; i < original.rowCount; ++i)
>         {
>             for (int j = 0; j < original.colCount; ++j)
>             {
>                 tab[i][j] = original.tab[i][j];
>             }
>         }
>         return *this;
>     }

Co znaczy nie możesz skopiować?
Programista napisał a=b; to wykonać razem ze zmianą rozmiaru, nie zapomnieć zwolnić starą pamięć.

>     void fill_tab()
>     {
>         for(int i = 0; i < rowCount; ++i)
>         {
>             for(int j = 0; j < colCount; ++j)
>             {
>                 //tab[i][j] = (rand() % 100) + 1;
>                 cout << "Enter [" << i << "][" << j << "] value : ";
>                 cin >> tab[i][j];
>             }
>             cout << endl;
>         }
> 
>     }

Zamiast fill_tab zrób:
friend std::istream &operator>>(std::istream& in, newSpace &obj)
komunikat: cout << "Enter [" << i << "][" << j << "] value : "; dawaj tylko wtedy gdy &in==&cin

>     friend std::ostream& operator<<(std::ostream& out, const newSpace & obj)
>     {
>         out << "\n";
>         for(int i = 0; i < obj.rowCount; ++i)
>         {
>             out << "Pole position " << i << setw(4) << std::setfill(' ') << right << "\t";
>             for(int j = 0; j < obj.colCount; ++j)
>             {
>                 out << setw(4) << std::setfill(' ') << right << obj.tab[i][j] << " ";
>             }
>             out << "\n";
>         }
>         out << "\n";
> 
>         return out;
>     }

Nie dawaj ostatniego entera, bo możesz go zawsze dodać razem z użyciem.
cout<<matrix<<endl;

>     void show_me(std::ostream& os)
>     {
>         for(int i = 0; i < rowCount; ++i)
>         {
>             os << "Pole position " << i << setw(4) << std::setfill(' ') << right << "\t";
>             for(int j = 0; j < colCount; ++j)
>             {
>                 os << setw(4) << std::setfill(' ') << right << tab[i][j] << " ";
>             }
>             os << "\n";
>         }
> 
>     }

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