delete [] wskaźnik

0

Kiedy destruktor wchodzi do gry to dostaje błąd. Chce opróżnić w moim przypadku wsk. Nie potrafię zrozumieć, czy źle staram się usunąć ten wsk, a może błąd leży gdzieś indziej?
Mój program ma za zadanie dodać do siebie poprzez operator + dwa punktnD, które mają w sobie wymiar i zależną od niego dynamiczną tablicę.

#include <iostream>
using namespace std;

class punktnD {
	int wymiar;
	int* wsk;
public :
	static int liczbaObiektow;
public:	
	punktnD(int n=2) :wymiar(n), wsk(new int[wymiar]) { 
		liczbaObiektow++; 
		cout << "konstruktor domyslny" << endl;
		cout << "wsk - " << *wsk << endl;
	}
	punktnD(const punktnD & pkt):wymiar(pkt.wymiar), wsk(new int[wymiar]) {
		int* tmp1 = pkt.wsk;
		int* tmp2 = wsk;

		for (int i = 0; i < wymiar; i++) {
			tmp2[i] = tmp1[i];
		}	
		cout << "konstruktor kopiujacy" << endl;
		liczbaObiektow++;
	}
	~punktnD() {
		liczbaObiektow--;
		delete [] wsk;
	}

	friend punktnD operator + (const punktnD& pkt1, const punktnD& pkt2) {
		punktnD pkt;
		if (pkt1.wymiar < pkt2.wymiar)
			pkt.wymiar = pkt2.wymiar;
		else pkt.wymiar = pkt1.wymiar;

		int* tmp1 = pkt1.wsk;
		int* tmp2 = pkt2.wsk;
		int* tmp3 = pkt.wsk;

		for (int i = 0; i < pkt.wymiar; i++) {
			tmp3[i] = tmp1[i] + tmp2[i];
		}

		return pkt;
	}
	
	friend istream& operator >> (istream& kl, punktnD& pkt) {
		for (int i = 0; i < pkt.wymiar; i++) {
			cout << "podaj " << i << " element" << endl;
			cin >> pkt.wsk[i];
		}
		return kl;
	}

	friend ostream& operator << (ostream& kl, punktnD& pkt)
	{
		for (int i = 0; i < pkt.wymiar; i++) {
			cout << "element " << i << " :" << pkt.wsk[i]<< endl;
		}
		return kl;
	}
};

int punktnD::liczbaObiektow = 0;
0

Bo prawdopodobnie mażesz po pamięci. W operator + przydzielasz tablicę na 2 elementy;

friend punktnD operator + (const punktnD& pkt1, const punktnD& pkt2)
    {
        punktnD pkt(pkt1.wymiar>pkt2.wymiar?pkt1.wymiar:pkt2.wymiar);
        for(int i=0;i<pkt.wymiar;++i)
        {
            pkt.wsk[i]=(i<pkt1.wymiar?pkt1.wsk[i]:0)+(i<pkt2.wymiar?pkt2.wsk[i]:0);
        }
        return pkt;
    }
0

Jaki Masz błąd, bo lekko zmieniony kod (komunikat w destruktorze), kompilluje się i wykonuje bez błędów (g++-9, Ubuntu):

#include <iostream>
using namespace std;

class punktnD {
    int wymiar;
    int* wsk;
public :
    static int liczbaObiektow;
public: 
    punktnD(int n=2) :wymiar(n), wsk(new int[wymiar]) { 
        liczbaObiektow++; 
        cout << "konstruktor domyslny" << endl;
        cout << "wsk - " << *wsk << endl;
    }
    punktnD(const punktnD & pkt):wymiar(pkt.wymiar), wsk(new int[wymiar]) {
        int* tmp1 = pkt.wsk;
        int* tmp2 = wsk;

        for (int i = 0; i < wymiar; i++) {
            tmp2[i] = tmp1[i];
        }   
        cout << "konstruktor kopiujacy" << endl;
        liczbaObiektow++;
    }
    ~punktnD() {
        std::cout <<" destr\n";
        liczbaObiektow--;
        delete [] wsk;
    }

    friend punktnD operator + (const punktnD& pkt1, const punktnD& pkt2) {
        punktnD pkt;
        if (pkt1.wymiar < pkt2.wymiar)
            pkt.wymiar = pkt2.wymiar;
        else pkt.wymiar = pkt1.wymiar;

        int* tmp1 = pkt1.wsk;
        int* tmp2 = pkt2.wsk;
        int* tmp3 = pkt.wsk;

        for (int i = 0; i < pkt.wymiar; i++) {
            tmp3[i] = tmp1[i] + tmp2[i];
        }

        return pkt;
    }

    friend istream& operator >> (istream& kl, punktnD& pkt) {
        for (int i = 0; i < pkt.wymiar; i++) {
            cout << "podaj " << i << " element" << endl;
            cin >> pkt.wsk[i];
        }
        return kl;
    }

    friend ostream& operator << (ostream& kl, punktnD& pkt)
    {
        for (int i = 0; i < pkt.wymiar; i++) {
            cout << "element " << i << " :" << pkt.wsk[i]<< endl;
        }
        return kl;
    }
};

int punktnD::liczbaObiektow = 0;

void test() {
     punktnD p{3};
}

int main() {
   test();
}
1

g++, by Cię poinformował czytelniej: double free detected ; nie Wywołuj destruktora, on się sam uruchamia, jak obiekt wychodzi ze "scope", czyli u Ciebie dwa razy, a to jest no, no ;)

2

Dodatkowa lektura:

1
  1. Zmień tablicę na vector
  2. Zastosuj CRTP jako mechanizm zliczania istniejących obiektów. Możesz zlikwidować własny konstruktor kopiujący i destruktor. Wtedy kompilator będzie mógł utworzyć niejawnie konstruktor i operator przenoszący. Co za tym idzie w operatorze dodawania zwracany obiekt będzie mógł być przeniesiony.
#include <iostream>
#include <vector>

using namespace std;

template <typename T>
struct Counter
{
    Counter(){ ++counter; }
    Counter( const Counter& ){ ++counter; }
    inline static int counter {0};

protected:
    ~Counter() { --counter; }
};

class Point : public Counter<Point>
{

    vector<int> component;

public:

    Point( int n=2 ){component.resize(n,n);}

    friend Point operator+( const Point& point1, const Point& point2 )
    {
        Point point { ((point1.component.size()>point2.component.size()) ? point1 : point2) };

        size_t index {0};
        for( const auto& value : ( (point1.component.size()<point2.component.size()) ? point1.component : point2.component ) )
        {
            point.component[index++] += value;
        }

        return point;
    }

    friend ostream& operator<<( ostream& out , const Point& point )
    {
        for( const auto& element : point.component )
        {
            out << element << " ";
        }
        return out;
    }


};

int main()
{
    Point p1 {10} , p2 {20};

    auto p = p1 + p2;

    cout << p1 << endl ;
    cout << p2 << endl ;
    cout << p << endl ;

    cout << Point::counter << endl;

    return 0;
}

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