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