При тестировании списка объектов Product программа просто завершает работу с кодом -1073741819(при выборе любой функции). Помогите найти ошибку.
шаблон для работы с двоичным файлом
#pragma once
#include <string>
#include <iostream>
#include <fstream>
#include <stdexcept>
#include <vector>
#include <algorithm>
#include <functional>
#define MAXitemsPerPage 30
template <typename T>
class Node {
public:
T data;
long next; // Указатель на следующий узел
long prev; // Указатель на предыдущий узел
// Конструктор с параметрами
Node(const T& data) : data(data), next(-1), prev(-1) {}
// Конструктор по умолчанию
Node() : data(T()), next(-1), prev(-1) {} // Инициализация data значением по умолчанию
};
template <typename T>
class BaseList {
public:
BaseList(const std::string& filename);
~BaseList();
void add(const T& item); // Добавление элемента
void remove(size_t index); // Удаление элемента по индексу
T get(size_t index); // Извлечение элемента по индексу
void insert(size_t index, const T& item); // Вставка элемента по логическому номеру
void update(size_t index, const T& item); // Обновление элемента
size_t getSize() const; // Получение размера списка
void display(); // Отображение списка
void displayPage(size_t pageNumber); // Постраничный просмотр
void sort(const std::function<bool(const T&, const T&)>& comparator);
void compressFile(const std::string& outputFile); // Сжатие файла
void loadFromFile(); // Загрузка из файла
void saveToFile() const; // Сохранение в файл
private:
long head; // Указатель на голову списка
long tail; // Указатель на конец списка
size_t size; // Размер списка
std::fstream file; // Файл для хранения данных
std::string filename; // Имя файла
};
template <typename T>
BaseList<T>::BaseList(const std::string& filename) : filename(filename), size(0), head(-1), tail(-1) {
file.open(filename, std::ios::binary | std::ios::in | std::ios::out);
if (!file.is_open()) {
file.open(filename, std::ios::binary | std::ios::out);
file.close();
file.open(filename, std::ios::binary | std::ios::in | std::ios::out);
}
loadFromFile();
}
template <typename T>
BaseList<T>::~BaseList() {
saveToFile();
file.close();
}
template <typename T>
void BaseList<T>::add(const T& item) {
Node<T> newNode(item);
long newNodePos = file.tellp(); // Позиция нового узла
file.seekp(0, std::ios::end);
file.write(reinterpret_cast<const char*>(&newNode), sizeof(Node<T>));
size++;
if (head == -1) {
head = newNodePos; // Если список пуст, новый узел - голова
tail = newNodePos; // И конец
}
else {
// Обновляем указатели
file.seekp(tail);
Node<T> tailNode;
file.read(reinterpret_cast<char*>(&tailNode), sizeof(Node<T>));
tailNode.next = newNodePos;
file.seekp(tail);
file.write(reinterpret_cast<const char*>(&tailNode), sizeof(Node<T>));
tail = newNodePos;
}
}
template <typename T>
void BaseList<T>::remove(size_t index) {
if (index >= size) throw std::out_of_range("Index out of range");
long currentPos = head;
long prevPos = -1;
for (size_t i = 0; i < index; ++i) {
prevPos = currentPos;
file.seekg(currentPos);
Node<T> currentNode;
file.read(reinterpret_cast<char*>(¤tNode), sizeof(Node<T>));
currentPos = currentNode.next;
}
// Удаляем узел
Node<T> currentNode;
file.seekg(currentPos);
file.read(reinterpret_cast<char*>(¤tNode), sizeof(Node<T>));
if (prevPos != -1) {
// Если не удаляем голову
file.seekp(prevPos);
Node<T> prevNode;
file.read(reinterpret_cast<char*>(&prevNode), sizeof(Node<T>));
prevNode.next = currentNode.next;
file.seekp(prevPos);
file.write(reinterpret_cast<const char*>(&prevNode), sizeof(Node<T>));
}
else {
// Если удаляем голову
head = currentNode.next;
}
if (currentNode.next != -1) {
// Если не удаляем последний элемент
file.seekp(currentNode.next);
Node<T> nextNode;
file.read(reinterpret_cast<char*>(&nextNode), sizeof(Node<T>));
nextNode.prev = prevPos;
file.seekp(currentNode.next);
file.write(reinterpret_cast<const char*>(&nextNode), sizeof(Node<T>));
}
else {
// Если удаляем последний элемент
tail = prevPos;
}
size--;
}
template <typename T>
T BaseList<T>::get(size_t index) {
if (index >= size) throw std::out_of_range("Index out of range");
long currentPos = head;
for (size_t i = 0; i < index; ++i) {
file.seekg(currentPos);
Node<T> currentNode;
file.read(reinterpret_cast<char*>(¤tNode), sizeof(Node<T>));
currentPos = currentNode.next;
}
file.seekg(currentPos);
Node<T> currentNode;
file.read(reinterpret_cast<char*>(¤tNode), sizeof(Node<T>));
return currentNode.data;
}
template <typename T>
void BaseList<T>::insert(size_t index, const T& item) {
if (index > size) throw std::out_of_range("Index out of range");
Node<T> newNode(item);
long newNodePos = file.tellp(); // Позиция нового узла
file.seekp(0, std::ios::end);
file.write(reinterpret_cast<const char*>(&newNode), sizeof(Node<T>));
size++;
if (index == 0) {
// Вставка в начало
newNode.next = head;
if (head != -1) {
file.seekp(head);
Node<T> headNode;
file.read(reinterpret_cast<char*>(&headNode), sizeof(Node<T>));
headNode.prev = newNodePos;
file.seekp(head);
file.write(reinterpret_cast<const char*>(&headNode), sizeof(Node<T>));
}
head = newNodePos;
newNode.prev = -1;
}
else {
// Вставка в середину или конец
long currentPos = head;
long prevPos = -1;
for (size_t i = 0; i < index; ++i) {
prevPos = currentPos;
file.seekg(currentPos);
Node<T> currentNode;
file.read(reinterpret_cast<char*>(¤tNode), sizeof(Node<T>));
currentPos = currentNode.next;
}
newNode.next = currentPos;
newNode.prev = prevPos;
if (prevPos != -1) {
file.seekp(prevPos);
Node<T> prevNode;
file.read(reinterpret_cast<char*>(&prevNode), sizeof(Node<T>));
prevNode.next = newNodePos;
file.seekp(prevPos);
file.write(reinterpret_cast<const char*>(&prevNode), sizeof(Node<T>));
}
if (currentPos != -1) {
file.seekp(currentPos);
Node<T> currentNode;
file.read(reinterpret_cast<char*>(¤tNode), sizeof(Node<T>));
currentNode.prev = newNodePos;
file.seekp(currentPos);
file.write(reinterpret_cast<const char*>(¤tNode), sizeof(Node<T>));
}
}
if (newNode.next == -1) {
tail = newNodePos; // Обновить tail, если вставка в конец
}
}
template <typename T>
void BaseList<T>::sort(const std::function<bool(const T&, const T&)>& comparator) {
std::vector<T> items;
long currentPos = head;
// Извлечение всех элементов в вектор
while (currentPos != -1) {
file.seekg(currentPos);
Node<T> currentNode;
file.read(reinterpret_cast<char*>(¤tNode), sizeof(Node<T>));
items.push_back(currentNode.data);
currentPos = currentNode.next;
}
// Сортировка вектора с использованием компаратора
std::sort(items.begin(), items.end(), comparator);
// Очистка текущего списка
head = -1;
tail = -1;
size = 0;
// Вставка отсортированных элементов обратно в список
for (const auto& item : items) {
add(item);
}
}
template <typename T>
void BaseList<T>::update(size_t index, const T& item) {
if (index >= size) throw std::out_of_range("Index out of range");
long currentPos = head;
for (size_t i = 0; i < index; ++i) {
file.seekg(currentPos);
Node<T> currentNode;
file.read(reinterpret_cast<char*>(¤tNode), sizeof(Node<T>));
currentPos = currentNode.next;
}
file.seekp(currentPos);
Node<T> currentNode;
file.read(reinterpret_cast<char*>(¤tNode), sizeof(Node<T>));
currentNode.data = item;
file.seekp(currentPos);
file.write(reinterpret_cast<const char*>(¤tNode), sizeof(Node<T>));
}
template <typename T>
size_t BaseList<T>::getSize() const {
return size;
}
template <typename T>
void BaseList<T>::display() {
long currentPos = head;
while (currentPos != -1) {
file.seekg(currentPos);
Node<T> currentNode;
file.read(reinterpret_cast<char*>(¤tNode), sizeof(Node<T>));
std::cout << currentNode.data << " ";
currentPos = currentNode.next;
}
std::cout << std::endl;
}
template <typename T>
void BaseList<T>::displayPage(size_t pageNumber) {
long currentPos = head;
size_t startIndex = (pageNumber - 1) * MAXitemsPerPage;
for (size_t i = 0; i < startIndex && currentPos != -1; ++i) {
file.seekg(currentPos);
Node<T> currentNode;
file.read(reinterpret_cast<char*>(¤tNode), sizeof(Node<T>));
currentPos = currentNode.next;
}
for (size_t i = 0; i < MAXitemsPerPage && currentPos != -1; ++i) {
file.seekg(currentPos);
Node<T> currentNode;
file.read(reinterpret_cast<char*>(¤tNode), sizeof(Node<T>));
std::cout << currentNode.data << " ";
currentPos = currentNode.next;
}
std::cout << std::endl;
}
template <typename T>
void BaseList<T>::compressFile(const std::string& outputFile) {
std::vector<T> uniqueItems;
long currentPos = head;
while (currentPos != -1) {
file.seekg(currentPos);
Node<T> currentNode;
file.read(reinterpret_cast<char*>(¤tNode), sizeof(Node<T>));
if (std::find(uniqueItems.begin(), uniqueItems.end(), currentNode.data) == uniqueItems.end()) {
uniqueItems.push_back(currentNode.data);
}
currentPos = currentNode.next;
}
std::ofstream outFile(outputFile, std::ios::binary);
for (const auto& uniqueItem : uniqueItems) {
outFile.write(reinterpret_cast<const char*>(&uniqueItem), sizeof(T));
}
outFile.close();
}
template <typename T>
void BaseList<T>::loadFromFile() {
file.seekg(0, std::ios::end);
size = file.tellg() / sizeof(Node<T>);
file.seekg(0, std::ios::beg);
}
template <typename T>
void BaseList<T>::saveToFile() const {
// Сохранение уже происходит в деструкторе
}
класс который работает с Product
#pragma once
#include "ClassProduct.h"
#include "BaseList.h"
#include <string>
#include <iostream>
#include <fstream>
#include <stdexcept>
#include <vector>
using namespace std;
class ProductList : public BaseList<Product> {
public:
ProductList(const std::string& filename) : BaseList<Product>(filename) {}
void sortByName();
void sortByCategory();
void sortByQuantity();
void sortByArrivalDate();
void sortByPrice();
void sortByMarkup();
void generateInvoice(); // Генерация счета
};
класс Product
#pragma once
#include <string>
#include <iostream>
#include <fstream>
#include <stdexcept>
using namespace std;
class Product {
public:
Product();
Product(const string& _name, const string& _category, int _quantity,
const string& _arrivalDate, double _price, double _markupPercentage);
Product(const Product& obj);
~Product();
// Геттеры
string getName() const;
string getCategory() const;
int getQuantity() const;
string getArrivalDate() const;
double getPrice() const;
double getMarkupPercentage() const;
// Сеттеры
void setName(const string& _name);
void setCategory(const string& _category);
void setQuantity(int _quantity);
void setArrivalDate(const string& _arrivalDate);
void setPrice(double _price);
void setMarkupPercentage(double _markupPercentage);
// Сериализация
void serialize(std::ostream& os) const;
void deserialize(std::istream& is);
// Операторы ввода-вывода
friend ostream& operator<<(ostream& os, const Product& product);
friend istream& operator>>(istream& is, Product& product);
bool operator==(const Product& other) const;
private:
string name;
string category;
int quantity;
string arrivalDate;
double price;
double markupPercentage;
};
функция теста
void testProductList() {
ProductList productList("testProductList2.bin");
Product product;
int choice;
while (true) {
std::cout << "Меню для тестирования списка продуктов:\n";
std::cout << "1. Добавить продукт\n";
std::cout << "2. Удалить продукт\n";
std::cout << "3. Обновить продукт\n";
std::cout << "4. Отобразить продукты\n";
std::cout << "5. Сортировать по имени\n";
std::cout << "6. Сортировать по цене\n";
std::cout << "7. Генерация счета\n";
std::cout << "8. Постраничный просмотр\n";
std::cout << "9. Вставить продукт\n";
std::cout << "10. Сжать файл\n";
std::cout << "11. Выход\n";
std::cout << "Выберите операцию: ";
std::cin >> choice;
switch (choice) {
case 1:
std::cout << "Введите данные продукта (имя, категория, количество, дата поступления, цена, наценка):\n";
std::cin >> product;
productList.add(product);
break;
case 2:
std::cout << "Введите индекс продукта для удаления: ";
std::cin >> choice;
try {
productList.remove(choice);
}
catch (const std::out_of_range& e) {
std::cout << e.what() << std::endl;
}
break;
case 3:
std::cout << "Введите индекс продукта для обновления: ";
std::cin >> choice;
if (choice < 0 || choice >= productList.getSize()) {
std::cout << "Индекс вне диапазона." << std::endl;
break;
}
std::cout << "Введите новые данные продукта (имя, категория, количество, дата поступления, цена, наценка):\n";
std::cin >> product; // Предполагается перегрузка оператора >>
try {
productList.update(choice, product); // Обновляем с новыми данными
}
catch (const std::out_of_range& e) {
std::cout << e.what() << std::endl;
}
break;
case 4:
productList.display();
break;
case 5:
productList.sortByName(); // Предполагается, что метод sortByName() существует
std::cout << "Список отсортирован по имени.\n";
break;
case 6:
productList.sortByPrice(); // Предполагается, что метод sortByPrice() существует
std::cout << "Список отсортирован по цене.\n";
break;
case 7:
productList.generateInvoice(); // Предполагается, что метод generateInvoice() существует
break;
case 8: {
size_t pageNumber;
std::cout << "Введите номер страницы: ";
std::cin >> pageNumber;
productList.displayPage(pageNumber);
break;
}
case 9: {
std::cout << "Введите индекс для вставки: ";
size_t index;
std::cin >> index;
std::cout << "Введите данные продукта (имя, категория, количество, дата поступления, цена, наценка):\n";
std::cin >> product;
try {
productList.insert(index, product);
}
catch (const std::out_of_range& e) {
std::cout << e.what() << std::endl;
}
break;
}
case 10: {
std::string outputFile;
std::cout << "Введите имя выходного файла: ";
std::cin >> outputFile;
productList.compressFile(outputFile);
std::cout << "Файл сжат в " << outputFile << std::endl;
break;
}
case 11:
return;
default:
std::cout << "Неверный выбор. Попробуйте снова.\n";
}
}
}