1

Тема: C++ Класи. Допоможіть знайти де я виходжу за межі масиву

Друзі, допоможіть. Створив клас Поштова скринька в яку я додаю повідомлення, виводжу їх на екран і видаляю.
Помітив наступну помилку: якщо додати 3 повідомлення (S1R1M1, S2R2M2, S3R3M3), потім видалити третє (2 по індексу), знову його додати, потім видалити перше (0 по індексу) і спробувати вивести повідомлення з індексом 1, то програма завершується з помилкою. Я так розумію, що щось десь виходить за межі масиву, але не розумію де.
Допоможіть розібратися. Усі маніпуляції проводив з Завданням 2! Ось код:

/*Розробіть клас Message, який моделює повідомлення електронної пошти.
Повідомлення містить одержувача, відправника, текст повідомлення, час створення.

Необхідні наступні функції-члени:
• конструктор, який приймає відправника і одержувача і встановлює часову відмітку (time stamp)
• Функція-член append, яка додає рядок тексту в тіло повідомлення
• Функція-член to_string, яка перетворює повідомлення в один довгий рядок, напр.: "From:

Harry Hacker\nTo: Rudolf Reindeer\n ..."
• Функція-член print, яка друкує текст повідомлення. Порада: Використовуйте to_string.

Для створення time stamp використайте функції і типи, визначені у ctime.h

Другий етап

Розробіть клас MessageBox, котрий моделює поштову скриньку.
Він повинен зберігати повідомлення у масиві (визначтеся, це має бути масив об'єктів, чи масив вказівників на об'єкти)

Реалізуйте наступні функції-члени:
Додавання нового повідомлення (void MessageBox::add_message(Message m);)
Повернути повідомлення по індексу (Message MessageBox::get_message(int i) const;)
Видалити повідомлення по індексу (void MessageBox::remove_message(int i);)
*/

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<ctime>
#include <string>
using namespace std;

#pragma region Task_1
class Message
{
    string sender;
    string receiver;
    time_t curr_time;
    string message_body;

public:
    Message()
    {

    }
    Message(const Message &obj)
    {
        sender = obj.sender;
        receiver = obj.receiver;
        curr_time = obj.curr_time;
        message_body = obj.message_body;
    }
    void add_message()
    {
        cout << "Enter e-mail of a sender : ";
        cin.ignore();
        getline(cin, sender);
        cout << "Enter e-mail of a receiver : ";
        getline(cin, receiver);
        append();
        curr_time = time(0);
    }

    //Функція-член append, яка додає рядок тексту в тіло повідомлення
    void append()
    {
        cout << "Type your message : " << endl;
        getline(cin, message_body);
    }

    //Функція-член to_string, яка перетворює повідомлення в один довгий рядок, напр.: "From: Harry Hacker\nTo: Rudolf Reindeer\n ..."

    string to_string()
    {

        string full = "From: " + sender + "\nTo: " + receiver + "\nMessage: " + message_body + "\nTime: " + ctime(&curr_time);
        return full;
    }

    //Функція-член print, яка друкує текст повідомлення. Порада: Використовуйте     to_string
    void print()
    {
        cout << to_string();
    }
};

void task1()
{
    Message *My = new Message();
    My->add_message();
    My->print();
    system("pause");
}
#pragma endregion

#pragma region Task_2

/*Другий етап

Розробіть клас MessageBox, котрий моделює поштову скриньку.
Він повинен зберігати повідомлення у масиві (визначтеся, це має бути масив об'єктів, чи масив вказівників на об'єкти)

Реалізуйте наступні функції-члени:
Додавання нового повідомлення (void MessageBox::add_message(Message m);)
Повернути повідомлення по індексу (Message MessageBox::get_message(int i) const;)
Видалити повідомлення по індексу (void MessageBox::remove_message(int i);)*/

class MessageBox
{
private:
    int size;
    Message *All;
public:

    MessageBox(int size)
    {
        size = 0;
        All = new Message[size];
    }

    //Додавання нового повідомлення (void MessageBox::add_message(Message m);)
#pragma region Add_Message
private:
    //void get_message_from_user(Message &single)
    //{
    //    single.add_message();
    //}

    void move_class(Message *dst)
    {
        for (Message *src_ptr = All, *dst_ptr = dst; src_ptr < All + size; ++dst_ptr, ++src_ptr)
        {
            *dst_ptr = *src_ptr;
        }
    }

    Message* AddClass()
    {
        int newSize = size + 1;
        Message *new_box = new Message[newSize];
        move_class(new_box);
        (new_box + newSize - 1)->add_message();
        //get_message_from_user(*(new_box + newSize - 1));

        size = newSize;
        delete[] All;
        All = NULL;
        return new_box;
    }

public:
    void add_message()
    {
        char YesOrNot;
        do
        {
            All = AddClass();
            cout << "Object added" << endl;
            do
            {
                cout << "Add another object? (y/n): ";
                cin >> YesOrNot;
            } while (YesOrNot != 'y' && YesOrNot != 'n');
        } while (YesOrNot != 'n');
    }
#pragma endregion

    //Повернути повідомлення по індексу (Message MessageBox::get_message(int i) const;)
#pragma region Show_message
private:
    bool check_index(const int index)
    {
        bool is_in = false;
        if (index >= 0 && index < size)
        {
            is_in = true;
        }
        return is_in;
    }
public:
    void show_message()
    {
        int index;
        char YesOrNo;
        do
        {
            cout << "Enter the index of a message to show : ";
            cin >> index;
            if (check_index(index))
            {
                (All + index)->print();
            }
            else
            {
                cout << endl << "***** Invalid index! *****" << endl << endl;
            }
            do
            {
                cout << "Show another message? (y/n): ";
                cin >> YesOrNo;
            } while (YesOrNo != 'y' && YesOrNo != 'n');
        } while (YesOrNo != 'n');
    }
#pragma endregion

    //Видалити повідомлення по індексу (void MessageBox::remove_message(int i);)
#pragma region Delete_message
private:
    Message *delete_1_message(const int index)
    {
        int new_size = size - 1;
        Message *new_All = new Message[new_size];
        for (Message *ptr = All, *dst = new_All; ptr < All + (size - 1); ++dst, ++ptr)
        {
            if (ptr == All + index)
            {
                ++ptr;
            }
            *dst = *ptr;
        }

        size = new_size;
        if (All != nullptr)
        {
            delete[] All;
            All = NULL;
        }
        return new_All;
    }
public:
    void delete_messages()
    {
        int index;
        char YesOrNo;
        do
        {
            cout << "Enter the index of a message to delete : ";
            cin >> index;
            if (check_index(index))
            {
                All = delete_1_message(index);
                cout << endl << "***** Message deleted *****" << endl << endl;
            }
            else
            {
                cout << endl << "***** Invalid index! *****" << endl << endl;
            }
            do
            {
                cout << "Delete another message? (y/n): ";
                cin >> YesOrNo;
            } while (YesOrNo != 'y' && YesOrNo != 'n');
        } while (YesOrNo != 'n');
    }
#pragma endregion
};

void task2()
{
    int size = 0;
    MessageBox box = MessageBox(size);
    enum Menu
    {
        exit, add, show, remove
    };
    int choice = 0;
    do
    {
        do
        {
            cout << "Choose action :" << endl
                << Menu::add << ". Add message to the box" << endl
                << Menu::show << ". Show message by index" << endl
                << Menu::remove << ". Delete message by index" << endl
                << Menu::exit << ". Exit" << endl << endl
                << "Make a choice : ";
            cin >> choice;
        } while (choice < Menu::exit && choice > Menu::remove);
        switch (choice)
        {
        case Menu::add: box.add_message();
            break;
        case Menu::show: box.show_message();
            break;
        case Menu::remove: box.delete_messages();
            break;
        case Menu::exit: cout << "Good bye!" << endl;
        default:
            break;
        }
    } while (choice != Menu::exit);
}
#pragma endregion 

void main()
{
    enum Menu
    {
        exit, t1, t2
    };
    int choice = 0;
    do
    {
        do
        {
            cout << "Choose action :" << endl
                << Menu::t1 << ". Task 1. Message" << endl
                << Menu::t2 << ". Task 2. Message box" << endl
                << Menu::exit << ". Exit" << endl << endl
                << "Make a choice : ";
            cin >> choice;
        } while (choice < Menu::exit && choice > Menu::t2);
        switch (choice)
        {
        case Menu::t1: task1();
            break;
        case Menu::t2: task2();
            break;
        case Menu::exit: cout << "Good bye!" << endl;
            break;
        default:
            break;
        }
    } while (choice != Menu::exit);
    system("pause");
}

2

Re: C++ Класи. Допоможіть знайти де я виходжу за межі масиву

Щоб це могло бути?

    MessageBox(int size)
    {
        size = 0;
        All = new Message[size];
    }

3

Re: C++ Класи. Допоможіть знайти де я виходжу за межі масиву

Щоб це могло бути?

ахаха. Це моя перша програма з класами і це мали бути 2 конструктори, а вийшов 2 в 1. ахаха.

П.С. я Знайшов в чому помилка, але не можу зрозуміти чому так відбувається. Поясніть, будь ласка.
Проблема полягала у наступному:
У мене був код для видалення повідомлення ось такий :

for (Message *ptr = All, *dst = new_All; ptr < All + (size - 1); ++dst, ++ptr) 
{ 
if (ptr == All + index) 
{ 
++ptr; 
} 
*dst = *ptr; 

}
а треба було записати:

for (Message *ptr = All, *dst = new_All; ptr < All + (size - 1); ++dst, ++ptr) 
{ 
if (dst == All + index) 
{ 
++ptr; 
} 
*dst = *ptr; 
}

Зміна тут:
if (PTR == All + index) —-------------— if (DST== All + index)

Те саме відбувається і коли працювати з індексами:

for(int i = 0, j = 0, i < size - 1, ==i, ==j)
{
if(i == index) // умова починає працювати, якщо j == index
{
i++; // ++i однаково не працює
}
dst[j] = src[i]
}

Хтось розуміє, різницю логіки виконання цих кодів?