How do you return a Class Object with a pointer member variable to a list/array?

So, I have created a derived class template called unorderedSet that uses a pointer member variable to hold the location of an array on the heap (using new).

I am trying to overload the arithmetic operators to find both the intersection and union of two different unorderedSet objects, but my code terminates at the end of the first overloaded function call with a warning saying “reference to stack memory associated with local variable ‘unSet’ returned [-Wreturn-stack-address].” I will post the relevant parts of my code below.

template <class elemType>
class unorderedSet: public unorderedArrayListType<elemType>
{
public:
  void insertAt(int location, const elemType& insertItem);
  void insertEnd(const elemType& insertItem);
  void replaceAt(int location, const elemType& repItem);
  const unorderedSet<elemType>& operator+(const unorderedSet<elemType>&);
  // Function to overload the binary operator + to find the union of a pair/group of sets
  // Postcondition: Finds the union of the sets

  const unorderedSet<elemType>& operator-(const unorderedSet<elemType>&);
  // Function to overload the binary operator - to find the intersection of a pair/group of sets
  // Postcondition: Finds the intersection of the sets
  
  unorderedSet(int size = 100);
  unorderedSet(const unorderedSet<elemType>& otherSet);
  ~unorderedSet();
  
protected:
  elemType *set;
  int length;
  int maxSize;
};

template <class elemType>
const unorderedSet<elemType>& unorderedSet<elemType>::operator+(const unorderedSet<elemType>& otherSet)
{
  unorderedSet<elemType> unSet(this->length + otherSet.length); // Initializes new set to hold values of the union set

  for (int i = 0; i < this->length; i++)
    unSet.insertEnd(this->list[i]); // Assigns all values of the activating operand to the union set using insertEnd
  
  for (int i = 0; i < otherSet.length; i++)
    unSet.insertEnd(otherSet.list[i]); // Calls insertEnd() to both check for duplicate values and add unique values to the union of the sets
  
  cout << "nnunSet:n";
  unSet.print(); // Checks the values of the union set 
  //This is the last block of code my program runs that I know of

  return unSet; // Should return the union set, but dumps the core at the moment
} // end operator overload

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

    this->maxSize = 100;
  }
  else
    this->maxSize = size;

    this->length = 0;

    set = new elemType[this->maxSize];
}

template <class elemType>
unorderedSet<elemType>::~unorderedSet()
{
  delete [] set;
}

template <class elemType>
unorderedSet<elemType>::unorderedSet(const unorderedSet<elemType>& otherSet)
{
  this->maxSize = otherSet.maxSize;
  this->length = otherSet.length;

  set = new elemType[this->maxSize];

  for (int j = 0; j < length; j++)
    set[j] = otherSet.set[j];
}

The cout statements before the return values are what allow me to check that the function is doing its job up to that point, and, so far, it all works as it should.

The following code comes from my test client program.

int main() 
{
  int intArr1[6] = {0, 1, 2, 3, 4, 5};
  unorderedSet<int> testIntSet1;

  for (int i = 0; i < (sizeof(intArr1) / sizeof(intArr1[0])); i++)
    testIntSet1.insertEnd(intArr1[i]);
  // Some more code before the function call
  
  int intArr2[6] = {0, 1, 3, 6, 7, 9};
  unorderedSet<int> testIntSet2, testIntSet3;

  for (int i = 0; i < (sizeof(intArr2) / sizeof(intArr2[0])); i++)
    testIntSet2.insertEnd(intArr2[i]);

  testIntSet3 = testIntSet1 + testIntSet2;
  // Some more code
  }

Nothing after the last line in the client program runs, so know that is the issue. What I’m struggling with is how to fix my operator overload function so that the return value does not return a reference to a memory address that is destroyed once the function ends. I have read a lot of posts on this site where users often suggest using either malloc or calloc, but I’m not sure that is what I need to do, so I figured I would post some code and ask you guys.

Answer

The issue is that you’re returning a reference to a stack object, who’s lifetime is the scope of the operator+ function.

template <class elemType>
const unorderedSet<elemType>& unorderedSet<elemType>::operator+(const unorderedSet<elemType>& otherSet)

Notice that you’re returning a const unorderedSet<elemType>&, a reference to the set.

All you have to do is return an object, which will be copied to the target variable (although compilers will most likely optimize this with RVO, eliminating the copy)

All this requires is changing the return type to be an object, rather than a reference:

template <class elemType>
const unorderedSet<elemType> unorderedSet<elemType>::operator+(const unorderedSet<elemType>& otherSet)