0

Set.h

#ifndef Set_h
#define Set_h

#include <iostream>
using namespace::std;

template <class T>
class Set {
    T* group;
    int size_group;
public:
    Set():group(NULL),size_group(0){};
    Set(T*,int);
    Set(const Set<T>&);
    ~Set();


    bool isThere(const T&)const;
    void getType()const;

    Set<T>& operator =(const Set<T>&);
    bool operator ==(const Set<T>&) const;
    void operator +=(const T);
    void operator -=(const T&);
    Set<T>& operator +(Set<T>&);
    Set<T>& operator -(const Set<T>&);
    bool operator >(const Set<T>&)const;
    friend ostream& operator <<(ostream&,const Set<T>&);

};

//Realizations

template <class T>
Set<T>::Set(T* gro,int size):group(gro),size_group(size){}

template <class T>
Set<T>::Set(const Set<T>& obj){ // c'Ctor (copy)
    this->size_group = obj.size_group;
    this->group = new T[this->size_group];
    for (int i = 0; i < size_group; i++) {
        group[i] = obj.group[i];
    }
}

template <class T>
void Set<T>::getType() const{
    cout << "The type is: " << typeid(group).name() << endl;
}

template <class T>
Set<T>& Set<T>::operator = (const Set<T>& obj){
    this->size_group = obj.size_group;
    this->group = new T[size_group];
    for (int i = 0; i < size_group; i++) {
        this->group[i] = obj.group[i];
    }
    return *this;
}

template <class T>
bool Set<T>::operator==(const Set<T>& obj) const{
    int count = 0;
    T temp;
    if(this->size_group != obj.size_group)
        return false;
    for (int i = 0; this->size_group; i++) {
        temp = this->group[i];
        count = 0;
        for (int j = 0; j < obj.size_group; j++) {
            if(temp == obj.group[j])
                count++;
        }
        if(count != 1)
            return false;
    }
    return true;
}

template <class T>
void Set<T>::operator+=(const T var){
    if(!isThere(var)){
        T* Temp = new T[this->size_group+1];
        for (int i = 0; i < this->size_group; i++)
            Temp[i] = this->group[i];
        Temp[size_group] = var;
        delete [] this->group;
        this->size_group++;
        this->group = Temp;
    }

}

template <class T>
Set<T>& Set<T>::operator+(Set<T>& obj){ //
    if(obj.size_group > this->size_group){
        for (int i = 0; i < obj.size_group; i++){
            for (int j = 0 ; j < this->size_group; j++){
                if(!this->isThere(obj.group[i]))
                    *this += obj.group[i];
            }
        }
        return *this;
    }else{
        for (int i = 0; i < this->size_group; i++){
            for (int j = 0 ; j < obj.size_group; j++){
                if(!obj.isThere(this->group[i]))
                    obj += this->group[i];
            }
        }
        return obj;
    }
}


template <class T>
bool Set<T>::isThere(const T& var) const{
    for (int i = 0; i < this->size_group; i++) {
        if(this->group[i] == var)
            return true;
    }
    return false;
}




template <class T>
Set<T>::~Set() {
    delete [] group;
}

#endif /* Set_h */

Main:

#include "Set.h"

int main() {
    int arr[] = {3,7,8,1};
    int arr2[] = {1,2,5};

    Set<int> j(arr,4),l(arr2,3),k;

    k = j + l;
}

I'm trying to merge two arrays, but my problem is with the method void Set<T>::operator+=(const T var) and this line delete [] this-> group;

I get this error:

Template & Exception (8421,0x1000dadc0) malloc: *** error for object 0x7ffeefbff400: pointer being Friday was not allocated
Template & Exception (8421,0x1000dadc0) malloc: *** set a breakpoint in malloc_error_break to debug
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770

1 Answers1

0

Your Set(T*,int) constructor is not allocating new[]'ed memory for group to point at, which means operator+= (and ~Set(), and operator=) will fail at runtime when they try to delete[] the memory that group points at, which in your example is local stack memory that main() owns and passes in to the j and l objects.

Your Set(T*,int) constructor must new[] the group array and copy the contents of the input gro array into it, similar to how your copy constructor does, eg:

template <class T>
Set<T>::Set(T* gro, int size) : group(NULL), size_group(0)
{
    size_group = size;
    group = new T[size];
    for (int i = 0; i < size; i++) {
        group[i] = gro[i];
    }
}

On a side note, your operator= is leaking memory, as it does not delete[] the current group array before assigning a new group array. It should be making a temporary array, similar to how your operator+= does, eg:

template <class T>
Set<T>& Set<T>::operator=(const Set<T>& obj)
{
    if (this != &obj){
        T* Temp = new T[obj.size_group];
        for (int i = 0; i < obj.size_group; i++)
            Temp[i] = obj.group[i];
        delete [] group;
        group = Temp;
        size_group = obj.size_group;
    }
    return *this;
}

Or better, use your copy constructor via the copy-swap idiom instead:

template <class T>
Set<T>& Set<T>::operator=(const Set<T>& obj)
{
    if (this != &obj){
        Set<T> temp(obj);
        std::swap(group, temp.group);
        std::swap(size_group, temp.size_group);
    }
    return *this;
}

Also, your operator+ is implemented all wrong. It needs to return a new Set that is the concatenation of the arrays of *this and obj, not modify obj or *this at all. As such, it needs to look more like this instead:

template <class T>
Set<T> Set<T>::operator+(const Set<T>& obj) const
{
    Set<T> res(*this);
    for (int i = 0; i < obj.size_group; i++) {
        res += obj.group[i];
    }
    return res;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • ok i understand why...but i send the address of arr[] from the main to my T* group why i should allocating new memory? can you explain to me please? – Roni Jack Vituli Jun 16 '20 at 21:16
  • @RoniJackVituli Because the rest of your `Set` class *expects* `group` to *ALWAYS* be pointing at `new[]`'ed memory. But you are not doing that in the `Set(T*,int)` constructor, which is what `main()` calls. So you get a runtime error when `delete[]` is called on memory that is owned by the local stack in `main()`. You can't just point `group` at whatever random memory the caller passes in. `Set` needs to be the one that allocates the memory that `group` points to. – Remy Lebeau Jun 16 '20 at 21:28
  • @RoniJackVituli The other scenario is if the user passed you `int *p = new int(0); Set(p, 1)`. Your destructor would then erroneously call `delete [] group;` when the memory was not allocated using `new[]`, but with simply `new`, thus the wrong form of `delete` would have been used. In other words, the `Set` class has no idea where that pointer that it gets comes from. – PaulMcKenzie Jun 16 '20 at 22:12