Я не могу понять где допустил ошибки при работе с памятью
такое дело,я не понимаю из-за чего появляются следующие ошибки:если в конструкторе копирования убрать вывод cout << this->index<<"W"; то после перестаёт работать ostream& operator<<(ostream &os, const CMass& a) при попытке вывода d(14 стр в main.cpp); Ещё при создании f(15 стр в main.cpp) вызывается функция setSize и когда я ввожу значение, выдаёт нарушение прав доступа при чтении по адресу. И в конце при выходе из программы выдаёт ошибку :/ Я не понимаю где накосячил.
main.cpp
#include "mass.h";
using namespace std;
int main()
{
cout << fixed;
srand(time(0));
setlocale(LC_ALL, "rus");
try
{
CMass <double>a(10, 7);
CMass <double>b(10, 5);
CMass <double>d = a;
cout << d;
CMass <double>f;
cout << f;
cout << "a = " << a;
cout << "b = " << b;
CMass <double>e(10, 1);
e = b - a;
cout << "b - a = " << e;
cout << "b + a = " << b + a;
cout << "d = " << d;
cout << b;
a -= b;
cout << a;
cout << a[16];
double* c = a.Find(1.3);
if (!c)
throw "Такого числа нет";
cout << *c;
a.Sort(1);
a.Sort(0);
}
catch (const char* ex)
{
cout << ex;
}
//cin.get();
return 0;
}
mass.h
#pragma once
#include <iostream>
#include <iomanip>
#include<cmath>
#ifndef MASS_H
#define MASS_H
using namespace std;
//Если не введён размер
void setSize(int&);
template <typename T>
class CMass
{
private:
int size;
T* mass;
int index;
public:
//Конструктор
CMass(int s = 0, int I = 0)
{
size = s;
while (size == 0)
setSize(size);
index = I;
mass = (T*)calloc(size,sizeof(T));
mass -= index;
initrand();
}
//Конструктор копирования
CMass(const CMass & other)
{
cout << this->index<<"W";
this->index = other.index;
this->size = other.size;
this->mass = new T[this->size];
for (int i = 0; i < size; i++)
this->mass[i+index] = other.mass[other.index + i];
cout << this->index<<"W";
}
//Поиск элемента
T* Find(T x)
{
for (int i = index; i < size + index; i++)
if (mass[i] == x)
return &mass[i];
return NULL;
}
//Сортировка элементов
void Sort(bool i)
{
if (i)//Если равен 1, тогда по возрастанию
{
for (int j = index; j < size + index; j++)
{
for (int h = j + 1; h < size + index; h++)
if (mass[j] > mass[h])
{
T tmp;
tmp = mass[j];
mass[j] = mass[h];
mass[h] = tmp;
}
}
}
else//Иначе по убыванию
for (int j = index; j < size + index; j++)
{
for (int h = j + 1; h < size + index; h++)
if (mass[j] < mass[h])
{
T tmp;
tmp = mass[j];
mass[j] = mass[h];
mass[h] = tmp;
}
}
}
//Генерация чисел
void initrand()
{
for (int i = index; i < size + index; i++)
mass[i] = (T)(round((rand() * (100. + 100) / RAND_MAX - 100)*10)/10);//округление,чтобы был удобен поиск элемента
}
//Индексирование
T& operator [](int CIndex)
{
if (CIndex<index || CIndex>index + size-1)
throw "Вы вышли за границы массива!";
return mass[CIndex];
}
//Вычитание и сложение
CMass<T> operator+(const CMass<T>& other)
{
CMass result(size,0);
if (size != other.size)
throw "Размерность массивов разная";
for (int i = 0; i < result.size; i++)
result.mass[result.index + i] = mass[index + i] + other.mass[other.index + i];
return result;
}
CMass<T> operator-(const CMass<T>& other)
{
CMass result(size, 0);
if (size != other.size)
throw "Размерность массивов разная";
for (int i = 0; i < result.size; i++)
result.mass[result.index + i] = mass[index + i] - other.mass[other.index + i];
return result;
}
CMass<T> operator+=(const CMass<T>& other)
{
return *this + other;
}
CMass<T> operator-=(const CMass<T>& other)
{
return *this - other;
}
friend void setSize(int& size);
friend ostream& operator<<(ostream &os, const CMass<T>& a)
{
for (int i = 0; i < a.size; i++)
os << setprecision(1) << a.mass[a.index + i] << " ";
return os << endl;
}
};
#endif
mass.cpp
#include "mass.h"
#include <cstring>
#include <iostream>
void setSize(int& size)
{
cout << "\nВведите размер массива: ";
cin >> size;
}
Ответы (1 шт):
Есть такое правило трех/правило пяти - если есть конструктор копирования, то должен быть и оператор копирования и вести они себя должны "идентично" ( а также деструктор).
Если в классе есть "голый, не прикрытый смартпоинтером" указатель, нужно обязательно их написать.
В Вашем коде есть конструктор копирования, а вот оператора присваивания нет, поэтому будет сгенерирован автоматически, который просто скопирует содержимое класса побитово. И два объекта будут хранить указатель на одну и ту же память. И первый деструктор ее освободит, а второй.... а второй а ничего ... деструктора то нет:) просто утечка памяти.
Смотрим дальше. Вы используете то calloc, то new. Так нельзя, нужно что то одно для одной переменной. Да, деструктора у Вас нет, поэтому эту ошибку не сразу словите.
Ещё дальше. Посмотрим а этот кусочек кода
this->mass = new T[this->size];
for (int i = 0; i < size; i++)
this->mass[i+index] = other.mass[other.index + i];
Очевидно, что размер mass равен size. Дальше идет цикл от 0 до size-1. А внутри цикла используется еще +index. Если index > 0, то гарантирован выход за пределы массива. И дальше этот паттерн повторяется много-много раз.
Я бы вместо указателя и размера использовал бы обычный std::vector. Много кода существенно упростится.