Вопрос

это моя функция addCard, которая принимает PlayingCard в качестве параметра, а затем передает адрес самого себя выделенному массиву указателей на объекты PlayingCard.

void cardHand::addCard(playingCard card) {
    theHand[nElems++] = &card;
} // addCard()

теперь, когда я запускаю свою программу, она работает нормально, но затем выходит из строя при вызове деструктора.

cardHand::~cardHand() {
    for(int c = 0;c<MAX;c++) {
        if(theHand[c] != NULL)
            delete theHand[c]; // here is the problem
    }
    delete [] theHand;
} // class destructor

происходит ли сбой из-за того, что я передаю адрес объекта PlayingCard только в функции addCard.должен ли это быть указатель вместо этого?

Это было полезно?

Решение

Проблема заключается вот в чем

void cardHand::addCard(playingCard card) { theHand[nElems++] = &card; }

Вы сохраняете адрес временного объекта card, который будет уничтожен в конце метода addCard.

И в вашем деструкторе вы пытаетесь удалить его снова.

У вас есть два варианта.

Первый:создайте addCard, чтобы принимать только конфигурацию карты, и создайте свою карту с new в addCard способ.
Второй:принимайте карту по указателю, но тогда деструктор вашего cardHand не может нести ответственность за удаление карты.А удаление выполнит объект колоды, который создал все карты.

Другие советы

Когда ты говоришь:

theHand[nElems++] = &card;

Вы сохраняете адрес параметра функции, который фактически является локальной переменной.Это всегда плохо, и в вашем случае это приводит к сбою при попытке удалить его.

Вы, вероятно, хотите что-то вроде:

theHand[nElems++] = new playingcCard( card );

но реальное решение состоит в том, чтобы использовать std::vector для PlayingCard и полностью отказаться от динамического распределения.

Вы используете C ++ как лучший C, и хотя это прекрасно для многих целей, это не идиоматический C ++.

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

Ваша рука должна быть объявлена примерно так:

std::vector< playingCard > hand;

Новые карты должны быть нанесены на него чем-то вроде этого:

hand.push_back( card );

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

Итак, учитывая другие ответы, мой способ сделать это - передать ссылку или указатель на playingCard.

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

Он разбивается на delete потому что он никогда не был выделен с new.

void cardHand::addCard(playingCard card) {
    theHand[nElems++] = &card;
} // addCard()

При вызове этой функции вы передаете временную копию игровой карты и записываете ее адрес.Хранение временных адресов запрещено, если вы действительно не знаете, что делаете.

Вместо этого измените это на что-то вроде

/** @param card card to add. Takes ownership. */
void cardHand::addCard(playingCard *card) {
    theHand[nElems++] = card;
} // addCard()

И в вызывающем коде передайте ему playingCard указатель на объект, возвращенный из new playingCard.

У него все еще есть проблема с передачей права собственности на объект, которая является распространенной причиной ошибок двойного удаления или утечек памяти.Хорошей привычкой является делать такие переводы явными с помощью комментариев к коду.

Правило глухого удара:Удаляйте только то, что вы выделили (либо с помощью new, либо с помощью memalloc)

Следовательно, ваш крах.

Причина, по которой это не работает, заключается в том, что вы передаете свой класс по значению в cardHand::addCard.
Итак, что делает компилятор, так это создает временную копию экземпляра вашего класса в стеке.
Поскольку он находится в стеке, он будет автоматически очищен, как только addCard возвращает функция.
Вы можете исправить это, передав свой playingCard экземпляр вместо этого в качестве указателя.
Однако, как уже говорили другие в этом посте, желательно не delete вещи, которые вы явно не new.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top