class operator + overloading only partially working


'm trying to overload the + operator in my derived class unorderedSet (the base class is unorderedArrayListType, then arrayListType) to input (not add) the unique values of the arrays in the sum of two unorderedSet objects to the array I'm assigning it to. But when I try this all except for the first 4 values are correctly added to the unorderedSet object I'm assigning the sum to. Here is the relevant code. After running it, the console also shows "free(): double free detected in tcache 2", then "exited, aborted".

here is main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <string>
#include "unorderedSet.h" 

using namespace std;

int main() {

  unorderedSet<int> oneSet;
  unorderedSet<int> twoSet;
  unorderedSet<int> threeSet;

  int one[5] = {1, 2, 3, 5, 7};
  int two[5] = {2, 3, 8, 9, 10};

  for(int i = 0; i < 5; i++) {
    oneSet.insertEnd(one[i]);
    twoSet.insertEnd(two[i]);
  }
  
  
  threeSet = oneSet + twoSet;
  cout << endl;

  //here threeSet should print "2 3 8 9 10 1 5 7", but instead it always prints "0 0 (third number is always a big random number like 31498256) 0 10 1 5 7"
  //so I don't know why the first four digits after assignment of threeSet is always incorrectly showing 0 0 31498256(or another random big number) 0...
  threeSet.print();

}


here are the relevant parts of unorderedSet.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#ifndef unorderedSet_H
#define unorderedSet_H

#include "unorderedArrayListType.h" 
using namespace std;

template <class elemType>
class unorderedSet: public unorderedArrayListType<elemType> {
  public:
    void insertEnd(const elemType& insertItem);
    unorderedSet<elemType> operator+(const unorderedSet<elemType>& other) const;
};

template <class elemType>
void unorderedSet<elemType>::insertEnd(const elemType& insertItem) {
  int loc = unorderedArrayListType<elemType>::seqSearch(insertItem);
  if(loc == -1) {
    unorderedArrayListType<elemType>::insertEnd(insertItem);
  }
}

template <class elemType>
unorderedSet<elemType> unorderedSet<elemType>::operator+(const unorderedSet<elemType>& other) const
{
  unorderedSet<elemType> tempSet;
  
  for(int i = 0; i < other.listSize(); i++) {
    tempSet.insertEnd(other.list[i]);
  }

  for(int i = 0; i < this->listSize(); i++) {
    if(tempSet.unorderedArrayListType<elemType>::seqSearch(this->list[i]) == -1) {
      tempSet.insertEnd(this->list[i]);
    }
  }

  //tempSet is correctly receiving the correct values, but when I return it to be assigned the assigned object is inccorect for the first 4 values. 

  return tempSet;
}


here is the relevant base class code arrayListType.h, which creates the list pointer array. I'm pretty sure that the problem is not in the unorderedArrayListType.h file so I'm not including it.
arrayListType.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#ifndef H_arrayListType
#define H_arrayListType

#include <assert.h>

using namespace std;
 
template <class elemType>
class arrayListType {
public:
    void print() const;
      //Function to output the elements of the list
      //Postcondition: Elements of the list are output on the 
      //               standard output device.

    arrayListType(int size = 100);
      //Constructor
      //Creates an array of the size specified by the 
      //parameter size. The default array size is 100.
      //Postcondition: The list points to the array, 
      //               length = 0, and maxSize = size;

    arrayListType (const arrayListType& otherList);
       //Copy constructor

    virtual ~arrayListType();
      //Destructor
      //Deallocate the memory occupied by the array.

protected:
    elemType *list;    //array to hold the list elements
    int length;   //variable to store the length of the list
    int maxSize;  //variable to store the maximum 
                  //size of the list
};

template <class elemType>
arrayListType<elemType>::arrayListType(int size)
{
    if (size <= 0)
    {
        cout << "The array size must be positive. Creating "
             << "an array of the size 100." << endl;

        maxSize = 100;
    }
    else
        maxSize = size;

    length = 0;

    list = new elemType[maxSize];
} //end constructor

template <class elemType>
arrayListType<elemType>::~arrayListType()
{
    delete [] list;
} //end destructor

template <class elemType>
arrayListType<elemType>::arrayListType(const arrayListType& otherList)
{
    maxSize = otherList.maxSize;
    length = otherList.length;

    list = new elemType[maxSize]; 	//create the array

    for (int j = 0; j < length; j++)  //copy otherList
        list [j] = otherList.list[j];
}//end copy constructor

#endif


I think the problem might be how I'm handling the copy constructor and it may have to do with the list* array being a pointer, but I'm not sure how to fix it. Any help would be appreciated.


*************EDIT*******************
here are parts of unorderedArrayListType.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <iostream>
#include "unorderedArrayListType.h" 

using namespace std; 
 
void unorderedArrayListType::insertAt(int location, 
                                      int insertItem) 
{
public:
    void insertEnd(const elemType& insertItem);
    int seqSearch(const elemType& searchItem) const;

    unorderedArrayListType(int size = 100);
      //Constructor
}; 

template <class elemType>
int unorderedArrayListType<elemType>::seqSearch(const elemType& searchItem) const
{
    int loc;
    bool found = false;

    loc = 0;

    while (loc < this->length && !found)
        if (this->list[loc] == searchItem)
            found = true;
        else
            loc++;

    if (found)
        return loc;
    else
        return -1;
} //end seqSearch

template <class elemType>
unorderedArrayListType<elemType>::unorderedArrayListType(int size)
                       : arrayListType<elemType>(size)
{
}  //end constructor

#endif

Last edited on
in order of importance:
- ¿why there is so much whitespace at the end of your post?
- «I'm pretty sure that the problem is not in the unorderedArrayListType.h file so I'm not including it.» don't care, need something compilable to debug it.
- going by lines 32-34 or unorderedSet.h you don't seem to understand how to use the interface of your class.
- «the console also shows "free(): double free detected in tcache 2"» you are lucky enough to get a runtime error message, start there
- ¿where's your assignment operator implementation?
Sorry about the whitespace, I tried to edit it out after I posted but it kept saying error for some reason. fixed now.

I will add the relevant parts of unorderedArrayListType.h in an edit after I post this.

in lines 32-34 of unorderedSet.h, how should I be using the interface there instead of how I'm currently using it?

As for the "free(): double free detected in tcache 2" message, a core dump file was also made with this and using gdb to check the core dump I get this information:
1
2
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x000055e2fb35fcc6 in ?? () 

This doesn't tell me much, but I'm almost sure that the problem is how I'm handling the list* pointer array as I said in my post.

I didn't make an assignment operator implementation because I figured that the copy constructor is good enough. When researching on how to debug this I came across the rule of three (https://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)) which reccomends I make an assignment operator but I don't think it's necessary because my copy constructor should handle everything correctly.

how should I be using the interface there instead of how I'm currently using it?

You are checking for duplicates but insertEnd already does that.

I didn't make an assignment operator implementation because I figured that the copy constructor is good enough.

The copy ctor will not magically affect the assignment operator. Since you haven't specified an assignment operator it will just default to a shallow copy of the sizes and the pointer. When operator+ ends the list will be destructed, which is why you see some garbage at the head. The double free occurs when the assigned-to object is destructed since it contains the exact same pointer and not an actual (deep) copy.
Last edited on
you're right, insertEnd is alreading checking for duplicates. I overlooked that and edited it appropriately.


I will make an assignment operator and see if that fixes it. Thanks for the input.
Dutch and ne555, thanks for pointing out that I needed the assignment operator. I made one and that solved my issue. The book I'm learning from said that the built-in assignment operator generally works well for classes without pointer variables, but not for classes with pointer variables. After making one, I'm no longer getting those junk values from before. Thanks a lot for the help and pointing this obvious mistake out.
Topic archived. No new replies allowed.