malloc: *** ошибка для объекта: освобожденный указатель не выделен - PullRequest
0 голосов
/ 08 июля 2019

Я получаю эту ошибку, когда запускаю свой код.Я не уверен, почему я продолжаю получать эту ошибку, потому что я вызываю delete для двух объектов, которые я выделил с помощью оператора new.

Я попытался запустить его в Xcode, и я получил thread 1: signal SIGABRT error.

PokerV2.cpp

int main() {    
    bool game_flag = true;

    Poker_Game game1;

    game1.initialise_game();

    game1.game_run();

    while (game_flag) { 
        char input = 'a';
        game_flag = false;
        game1.game_run(game1.get_current_players());
        std::cout << "Press 'y' to continue";
        std::cin >> input;
        if (input == 'y') {
            game_flag = true;
        }
    }
}

poker_game_class.hpp

void Poker_Game::game_run() {
    int lowest = 10;
    int num = 0;
    // Create the deck and table dynamically
    Deck *deck = new Deck();
    Table *table = new Table(_player_num);

    deck->deal_cards(table->get_all_players(), _player_num, *table);

    for (int i = 0; i < 4; i++) {
        table->set_game_flag(i);
        table->set_highest_bet(0);

        for (int z = 0; z < table->get_player_num(); z++) {
            table->players_turn(z);
        }
    }

    for (int i = 0; i < table->get_player_num(); i++) {
        if (table->get_player(i).calculate_score(*table) < lowest) {
            num = i;
        }
    }

    std::cout << "The winner is player: " << num << "\n";
    std::cout << "The winner has won: £" << table->get_pot() << "\n";

    //Add total pot to players cash

    float current_balance = table->get_player(num).get_balance();
    float balance_after_win = current_balance + table->get_pot();

    table->get_player(num).set_balance(balance_after_win);

    std::cout << "Winners balance: £" << table->get_player(num).get_balance();

    this->Current_players = table->get_all_players();

    delete deck;
    delete table;
}

Ошибка возникает в *Функция 1018 * работает только при удалении deck и table.

Вывод с терминала

Ниже приведен связанный репозиторий GitHub

https://github.com/mbh1620/PokerV2/tree/master/PokerV2

1 Ответ

2 голосов
/ 08 июля 2019

У вас проблема здесь:

Player * Table::get_all_players()
{
    return Players;
}

Вы возвращаете указатель (и владельца) на Poker_Game, когда он вызывает эту функцию:

    // One place you call it from.
    set_current_players(table -> get_all_players());

Проблема в том, что два объекта теперь требуют владения Players, и оба вызывают delete [] на имеющемся у них указателе.

Poker_Game::~Poker_Game()
{
    delete[] Current_players;
}
Table::~Table()
{
    delete[] Players;
}

Не говорю, что это ваша единственная ошибка.

Вы в основном попали в ловушку семантики плохого владения в вашем приложении. В C ++ мы решили эту проблему (в отличие от C), используя специальные типы и языковые конструкции для явного обозначения владельца. Таким образом, мы точно знаем, кому принадлежит объект и, следовательно, кто отвечает за его удаление.

Ваши проблемы можно легко решить, выполнив несколько действий.

  1. Не выделять динамически массивы.
    Используйте std::vector<> для управления выделением для вас.
  2. Не выделять объекты динамически, срок жизни которых не дольше, чем функция.
    Просто используйте локальную переменную и позвольте правилам области видимости обработать ее.
  3. Если вам необходимо динамически выделить объект, используйте умный указатель.
    std :: unique_ptr и std :: shared_ptr очень хорошо управляют памятью для выделенных объектов.
  4. Если вы передаете объект другому объекту (и не передаете права собственности), тогда передайте по ссылке (а не по указателю).
    Это говорит другому классу, что они не владеют объектом и, следовательно, не должны его удалять.

Простое правило, которым следует жить, - это «Разделение проблем».

Класс должен быть либо бизнес-логикой, либо управлением ресурсами. Таким образом, ваш класс должен либо обрабатывать логику покера, либо они должны обрабатывать логику управления памятью, которую вы выделяете (не обе). Таким образом, любой класс, который обрабатывает покер, не должен вызывать новый / удалять класс, который обрабатывает новый / удалять, в нем не должно быть покерной логики.

Теперь стандартные библиотеки предоставляют много кода для управления ресурсами, поэтому вам не нужно, вы можете просто использовать существующий код и сосредоточиться на своей покерной логике. Если после того, как игра заработает, вы решите, что стандартное управление ресурсами недостаточно эффективно, и вы можете сосредоточиться на его обновлении как отдельной задаче.

...