Ошибка сегментации при перегрузке оператора =
У меня возникла ошибка 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.