Как вы возвращаете объект класса с переменной-членом указателя в список/массив?

#c

Вопрос:

Итак, я создал шаблон производного класса под названием unorderedSet, который использует переменную-член указателя для хранения местоположения массива в куче (используя new).

Я пытаюсь перегрузить арифметические операторы, чтобы найти пересечение и объединение двух разных объектов unorderedSet, но мой код завершается в конце первого вызова перегруженной функции с предупреждением «ссылка на память стека, связанную с возвращенной локальной переменной «unSet» [- Wret-адрес стека]». Я опубликую соответствующие части своего кода ниже.

 template <class elemType>
class unorderedSet: public unorderedArrayListType<elemType>
{
public:
  void insertAt(int location, const elemTypeamp; insertItem);
  void insertEnd(const elemTypeamp; insertItem);
  void replaceAt(int location, const elemTypeamp; repItem);
  const unorderedSet<elemType>amp; operator (const unorderedSet<elemType>amp;);
  // 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>amp; operator-(const unorderedSet<elemType>amp;);
  // 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>amp; otherSet);
  ~unorderedSet();
  
protected:
  elemType *set;
  int length;
  int maxSize;
};

template <class elemType>
const unorderedSet<elemType>amp; unorderedSet<elemType>::operator (const unorderedSet<elemType>amp; 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>amp; 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];
}
 

Операторы cout перед возвращаемыми значениями позволяют мне проверить, выполняет ли функция свою работу до этого момента, и до сих пор все работает так, как должно.

Следующий код взят из моей тестовой клиентской программы.

 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
  }
 

После последней строки в клиентской программе ничего не запускается, поэтому знайте, что в этом проблема. С чем я борюсь, так это с тем, как исправить мою функцию перегрузки оператора, чтобы возвращаемое значение не возвращало ссылку на адрес памяти, который уничтожается после завершения функции. Я прочитал много сообщений на этом сайте, где пользователи часто предлагают использовать либо malloc, либо calloc, но я не уверен, что это то, что мне нужно сделать, поэтому я решил опубликовать какой-нибудь код и спросить вас, ребята.

Ответ №1:

Проблема в том, что вы возвращаете ссылку на объект стека, время жизни которого является областью действия operator функции.

 template <class elemType>
const unorderedSet<elemType>amp; unorderedSet<elemType>::operator (const unorderedSet<elemType>amp; otherSet)
 

Обратите внимание , что вы возвращаете const unorderedSet<elemType>amp; ссылку на набор.

Все, что вам нужно сделать, это вернуть объект, который будет скопирован в целевую переменную (хотя компиляторы, скорее всего, оптимизируют это с помощью RVO, исключив копирование).

Все, что для этого требуется, — это изменить тип возвращаемого значения на объект, а не на ссылку:

 template <class elemType>
const unorderedSet<elemType> unorderedSet<elemType>::operator (const unorderedSet<elemType>amp; otherSet)
 

Комментарии:

1. Спасибо! Я даже не потрудился удалить оператор ссылки в своих попытках исправить свой код, но это было именно то, что требовалось. Я оставил его, потому что в большинстве примеров, которые я видел для перегрузки операторов, они включали » amp; » сразу после типа возвращаемого класса.