Ошибка сегментации при перегрузке оператора =

У меня возникла ошибка seg при перегрузке оператора присваивания для класса FeatureRandomCounts, который имеет _rects как его указательный элемент, указывающий на массив FeatureCount и размер rhs._dim, а другие члены даты не являются указателями:

FeatureRandomCounts &  FeatureRandomCounts::operator=(const FeatureRandomCounts &rhs)  
{  
  if (_rects) delete [] _rects;  

  *this = rhs;  // segment fault

  _rects = new FeatureCount [rhs._dim];  
  for (int i = 0; i < rhs._dim; i++)  
  {  
    _rects[i]=rhs._rects[i];  
  }  

  return *this;    
}

Есть ли у кого-то подсказки? Спасибо и приветствую!

Ответ 1

Как уже упоминалось, у вас бесконечная рекурсия; однако, чтобы добавить к этому, здесь надежный способ реализовать op =:

struct T {
  T(T const& other);
  T& operator=(T copy) {
    swap(*this, copy);
    return *this;
  }
  friend void swap(T& a, T& b);
};

Напишите правильную копию ctor и swap, а также безопасность исключений и все крайние случаи обрабатываются для вас!

Параметр копирования передается по значению и затем изменяется. Любые ресурсы, которые должен уничтожить текущий экземпляр, обрабатываются при уничтожении копии. Это следует за текущие рекомендации и обрабатывает самоопределение чисто.


#include <algorithm>
#include <iostream>

struct ConcreteExample {
  int* p;
  std::string s;

  ConcreteExample(int n, char const* s) : p(new int(n)), s(s) {}
  ConcreteExample(ConcreteExample const& other)
  : p(new int(*other.p)), s(other.s) {}
  ~ConcreteExample() { delete p; }

  ConcreteExample& operator=(ConcreteExample copy) {
    swap(*this, copy);
    return *this;
  }

  friend void swap(ConcreteExample& a, ConcreteExample& b) {
    using std::swap;
    //using boost::swap; // if available
    swap(a.p, b.p); // uses ADL (when p has a different type), the whole reason
    swap(a.s, b.s); // this 'method' is not really a member (so it can be used
                    // the same way)
  }
};

int main() {
  ConcreteExample a (3, "a"), b (5, "b");
  std::cout << a.s << *a.p << ' ' << b.s << *b.p << '\n';
  a = b;
  std::cout << a.s << *a.p << ' ' << b.s << *b.p << '\n';
  return 0;
}

Обратите внимание, что он работает с членами (p), управляемыми вручную, или членами (-ами) стиля RAII/SBRM.

Ответ 2

*this = rhs;

вызывает operator =(), который является функцией, которую вы пишете. Cue бесконечная рекурсия, переполнение стека, сбой.

Кроме того, если вы использовали std::vector, а не массив C-style, вам, вероятно, вообще не понадобилось бы использовать operator =().

Ответ 3

 *this = rhs;  // segment fault

Это окончательно не способ сделать это. Вы вызываете = рекурсивно, не вызывая встроенный оператор присваивания. Назначьте переменные по одному. Не ленитесь.

Ответ 4

Следующая строка:

  *this = rhs;  // segment fault

будет рекурсивно вызывать вашу функцию operator=(), что приведет к переполнению стека.

Вероятно, вы должны заменить его прямыми присваиваниями различных полей-членов.

Как сказал Нил, использование чего-то типа std::vector<> удалит большую часть ответственности за пределы вашего кода. Если по какой-либо причине вы не можете или не хотите использовать std::vector<>, вам также может потребоваться использовать "переменную подкачки" для вашего оператора присваивания. Это сделает исключение функции безопасным (если распределение памяти для массива FeatureCount завершается с ошибкой и генерирует исключение, исходный объект, которому назначено, будет оставлен без изменений). Что-то вроде следующего:

void FeatureRandomCounts::swap( FeatureRandomCounts& other)
{
    FeatureCount* tmp_rects = other._rects;
    int tmp_dim             = other._dim;    // or whatever type _dim is

    // similarly for other members of FeatureRandomCounts...

    // now copy the other contents to 
    this->_rects = other._rects;
    this->_dim   = other._dim;

    // assign other members of rhs to lhs

    other._rects = tmp_rects;
    other._dim   = tmp_dim;

    // etc.

    return;
}

Теперь ваше назначение может выглядеть так:

FeatureRandomCounts &  FeatureRandomCounts::operator=(const FeatureRandomCounts &rhs)  
{  
    FeatureRandomCounts tmp( rhs);  // make a copy

    tmp.swap( *this);               // swap the contents of the copy and *this

    return *this;
                                    // the contents of tmp (which has the old 
                                    //  stuff that was in *this) gets destructed
}

Обратите внимание, что для этого вам нужен правильный конструктор копирования, но, учитывая правило Big 3, вам уже нужна правильная копия ctor.