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

Я только что получил ошибку 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;    
}

У кого-то есть подсказка? Спасибо и всего наилучшего!

4 ответа

Решение

Как уже упоминалось, у вас есть бесконечная рекурсия; однако, чтобы добавить к этому, вот надежный способ реализовать 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.

*this = rhs;

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

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

 *this = rhs;  // segment fault

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

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

  *this = rhs;  // segment fault

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

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

Как сказал Нил, используя что-то вроде std::vector<> снимет большую часть ответственности с вашего кода. Если по какой-либо причине вы не можете или не хотите использовать std::vector<>Вы также можете рассмотреть возможность использования идиомы "swap" для своего оператора присваивания. Это сделает функцию исключения безопасной (если выделение памяти для 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 копирования.

Другие вопросы по тегам