После оператора не вызывается деструктор
class Test2 {
private:
unsigned char* arr;
size_t size;
public:
~Test2() {
free(this->arr);
this->size = 0;
}
Test2(size_t size) {
this->size = size;
this->arr = (unsigned char*)calloc(size, sizeof(this->arr));
}
Test2(Test2 const& copy) : size(copy.size), arr(new unsigned char[copy.size]){
memcpy(this->arr, copy.arr, copy.size);
}
Test2(Test2&& x) noexcept {
free(this->arr);
this->size = x.size;
this->arr = x.arr;
}
void Resize(size_t newsize) {
this->arr = (unsigned char*)realloc(this->arr, newsize);
for (size_t i = this->size; i < newsize; i++) {
this->arr[i] = 0;
}
this->size = newsize;
}
void Set(size_t index, unsigned char value) {
if (index < size) {
this->arr[index] = value;
}
else {
throw new exception("Out of bounds of an array");
}
}
Test2& operator<<(size_t N) {
Test2* c = new Test2(this->size + N);
for (size_t i = N; i < this->size + N; i++) {
c->Set(i, this->arr[i - N]);
}
return *c;
}
Test2& operator=(const Test2& rhs) {
if (this != &rhs) {
free(this->arr);
memcpy(this->arr, rhs.arr, rhs.size);
this->size = rhs.size;
}
return *this;
}
Test2& operator=(Test2&& rhs) noexcept {
if (this != &rhs) {
free(this->arr);
this->arr = rhs.arr;
this->size = rhs.size;
rhs.arr = nullptr;
rhs.size = 0;
}
return *this;
}
};
int main() {
Test2 a(3); //1, 0, 1
a.Set(0, 1);
a.Set(2, 1);
//Test2 b = a << 3;
Test2 b(1);
b = a << 3;
}
Выполняется оператор << потом оператор присваивания копированием, а временная переменная c так и не удаляется. Еще и в конце кода вызываются деструкторы a и b и в b происходит ошибка нарушение прав доступа при чтении по адресу. Если сделать как в закомментированной части кода, то этой ошибки нет и вызывается оператор копирования, но временная переменная так же не очищается. Я проверял содержимое этой переменной после выполнения кода и убедился что там все то же что и в b, только адреса другие. Как правильно сделать класс, чтобы временная переменная c очищалась и не происходило ошибок в деструкторе b? Если временную переменную делать в стеке, то он вызовет деструктор раньше конструктора копирования и в итоге скопируется мусор. Конструктор и оператор перемещения вообще не вызываются...
Ответы (2 шт):
class Test2 {
private:
unsigned char* arr;
size_t size;
public:
~Test2() {
free(this->arr);
this->size = 0;
}
Test2(size_t size) {
this->size = size;
this->arr = (unsigned char*)calloc(size, sizeof(this->arr));
}
Test2(Test2 const& copy) : size(copy.size), arr(new unsigned char[copy.size]){
memcpy(this->arr, copy.arr, copy.size);
}
Test2(Test2&& x) noexcept {
this->size = x.size;
this->arr = x.arr;
x.arr = nullptr;
x.size = 0;
}
void Resize(size_t newsize) {
this->arr = (unsigned char*)realloc(this->arr, newsize);
for (size_t i = this->size; i < newsize; i++) {
this->arr[i] = 0;
}
this->size = newsize;
}
void Set(size_t index, unsigned char value) {
if (index < size) {
this->arr[index] = value;
}
else {
throw new exception("Out of bounds of an array");
}
}
Test2 operator<<(size_t N) {
Test2 c(this->size + N);
for (size_t i = N; i < this->size + N; i++) {
c.Set(i, this->arr[i - N]);
}
return c;
}
Test2& operator=(const Test2& rhs) {
if (this != &rhs) {
free(this->arr);
memcpy(this->arr, rhs.arr, rhs.size);
this->size = rhs.size;
}
return *this;
}
Test2& operator=(Test2&& rhs) noexcept {
if (this != &rhs) {
free(this->arr);
this->arr = rhs.arr;
this->size = rhs.size;
rhs.arr = nullptr;
rhs.size = 0;
}
return *this;
}
};
int main() {
Test2 a(3); //1, 0, 1
a.Set(0, 1);
a.Set(2, 1);
//Test2 b = a << 3;
Test2 b(1);
b = a << 3;
}
Такой вариант работает, теперь временная переменная удаляется после вызова конструктора перемещения. Вот только я не понял почему до этого через стек вызывало деструктор до перемещения.
Даже непонятно, какой вариант разбирать - старый или новый... Наверное, возьмемся за новый.
Сразу общее: вы нигде не проверяете результат выделения/перераспределения памяти. И вообще используете в C++ работу с памятью в стиле C...
А дальше - см. комментарии к коду.
class Test2 {
private:
unsigned char* arr;
size_t size;
public:
~Test2() {
free(this->arr);
this->size = 0; // Просто не имеет смысла
}
Test2(size_t size) {
this->size = size;
// this->arr = (unsigned char*)calloc(size, sizeof(this->arr));
// Зачем здесь память для size УКАЗАТЕЛЕЙ? логичнее уж calloc(size, sizeof(*this->arr));
// Хотя самое логичное - new unsigned char [size]. C++ все же...
this->arr = (unsigned char*)calloc(size, sizeof(*this->arr));
}
Test2(Test2 const& copy) : size(copy.size),
// arr(new unsigned char[copy.size])
// Ай-я-яй!!! Запрещено смешивать два варианта! Или С'шный, или С++
arr((unsigned char *)malloc(sizeof(unsigned char)*copy.size))
{
memcpy(this->arr, copy.arr, copy.size);
}
Test2(Test2&& x) noexcept {
this->size = x.size;
this->arr = x.arr;
x.arr = nullptr;
x.size = 0;
}
void Resize(size_t newsize) {
this->arr = (unsigned char*)realloc(this->arr, newsize);
// А вы уверены, что увеличение будет только в большую сторону?...
for (size_t i = this->size; i < newsize; i++) {
this->arr[i] = 0;
}
this->size = newsize;
}
void Set(size_t index, unsigned char value) {
if (index < size) {
this->arr[index] = value;
}
else {
throw new exception("Out of bounds of an array");
}
}
Test2 operator<<(size_t N) {
// Логику - что вы хотите получить - что-то не понимаю...
// Но криминала не вижу.
Test2 c(this->size + N);
for (size_t i = N; i < this->size + N; i++) {
c.Set(i, this->arr[i - N]);
}
return c;
}
Test2& operator=(const Test2& rhs) {
if (this != &rhs) {
free(this->arr);
// И КУДА вы копируете?! В освобожденную память?!
// А новую выделять кто будет - Дейкстра?
arr = (unsigned char *)malloc(rhs.size*sizeof(unsigned char));
memcpy(this->arr, rhs.arr, rhs.size);
this->size = rhs.size;
}
return *this;
}
Test2& operator=(Test2&& rhs) noexcept {
if (this != &rhs) {
free(this->arr);
this->arr = rhs.arr;
this->size = rhs.size;
rhs.arr = nullptr;
rhs.size = 0;
}
return *this;
}
};
int main() {
Test2 a(3); //1, 0, 1
a.Set(0, 1);
a.Set(2, 1);
//Test2 b = a << 3;
Test2 b(1);
b = a << 3;
}
Немного о ваших исправлениях...
Было в старом совсем страшно:
Test2(Test2&& x) noexcept {
free(this->arr); // Что вы удаляете? Эта память не выделялась!
this->size = x.size;
this->arr = x.arr; // Теперь у вас два указателя указывают на одну память
// и два деструктора будут ее пытаться дважды освободить
В операторе << вы просто обеспечивали себе утечку памяти...
Да, тут
Test2 b = a << 3;
вызывается конструктор копирования, а тут - обычный конструктор
Test2 b(1);
и присвоение
b = a << 3;