Функция STACK.peek, возникли проблемы, C ++ - PullRequest
0 голосов
/ 06 апреля 2011
CARD& STACK::peek()
{
    if(cards.size == 0)
    {
        CARD temp = CARD {-1, -1};
        return temp;
    }
    return cards.back();
}

Это функция, с которой у меня проблемы.

  • CARD - это просто struct с двумя int переменными, называемыми rank и suit.

  • STACK - это class, управляющий std::vector<CARD>, который называется cards.

Функция должна возвращать reference на карту в верхней частистек или вернуть ссылку на фиктивную карту, если vector пусто.

Прежде всего, я получаю предупреждение о том, что возвращается ссылка на локальную переменную temp.Что не так с этим?Как это повлияет на функцию?Что мне с этим делать?

Во-вторых, я пытаюсь использовать эту функцию с другой созданной мной функцией с именем cardToString

char* cardToString(CARD& c);

Предполагается использовать rank иsuit переменных в переданном CARD для поиска строковых значений в таблице, объединения двух строк и возврата указателя на новую строку.

Таким образом, конечный результат выглядит следующим образом:

cout<<cardToString(deck.peek())<<"\n";

но эта строка кода будет выполняться до функции cardToString, а затем просто остановится по какой-то причине.Это чертовски раздражает меня, потому что оно просто останавливается, нет сообщения об ошибке и не похоже, что со мной что-то не так.

Может кто-нибудь мне помочь?

Править: здесь есть функция cardToString

char *cardToString(const CARD& c)
{
    if(c.r >= 13 || c.r < 0 || c.s >= 4 || c.s < 0)
    {
        std::cout<<"returned null";
        return NULL;
    }

    char *buffer = new char[32];

    strcpy(buffer, RANKS[c.r]);
    strcat(buffer, " of ");
    return strcat(buffer, SUITS[c.s]);
}

Я специально хочу, чтобы функция STACK.peek() возвращала адрес CARD, который уже существует в верхней части STACK.Кажется, имеет смысл сделать это, чем создать копию карты, которую я хочу вернуть.

Ответы [ 2 ]

3 голосов
/ 06 апреля 2011

Прежде всего, я получаю предупреждение о том, что возвращается ссылка на локальную переменную temp. Что не так с этим? Как это повлияет на функцию? Что мне с этим делать?

Локальная переменная, как следует из названия, является локальной для функции, которой она принадлежит, поэтому она уничтожается при возврате функции; если вы попытаетесь вернуть ссылку на него, вы вернете ссылку на то, что перестанет существовать в тот самый момент, когда функция вернется.

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

У вас есть два варианта: во-первых, вы можете вернуть CARD по значению вместо ссылки; это, однако, имеет тот недостаток, что не позволяет вызывающей стороне использовать ссылку для изменения CARD, как это хранится в vector (это может или не может быть желательно).

Другой подход заключается в хранении статического фиктивного экземпляра CARD в классе STACK, который не будет иметь таких проблем при жизни, и который может быть возвращен, если у вас нет элементов в vector; тем не менее, вы должны найти метод для «защиты» своего поля, в противном случае «глупый» вызывающий может изменить значения вашего «одиночного» фиктивного элемента, что испортит логику класса. Можно изменить CARD на class, который будет инкапсулировать его поля и запретит доступ на запись к ним, если это фиктивный элемент.

Что касается функции cardToString, вы, вероятно, делаете что-то не так со строками (и я почти уверен, что вы пытаетесь вернуть локальное также и в этом случае), но не видя тела функции трудно сказать что.

Кстати, чтобы избежать многих проблем со строками, я предлагаю вместо char * использовать класс std::string, который устраняет большую часть уродства и низкоуровневое управление памятью у обычного char *.

Кроме того, я бы предложил вам изменить cardToString на const ссылку, потому что, скорее всего, не нужно изменять объект, переданный в качестве ссылки, и хорошей практикой является четкое обозначение этого факта ( компилятор предупредит вас, если вы попытаетесь изменить такую ​​ссылку).

<ч />

Редактировать Функция cardToString должна работать нормально, если с массивами RANKS и SUITS все в порядке. Но , если вы использовали эту функцию, как написали, вы теряете память, так как для каждого вызова cardToString вы делаете выделение с new, которое никогда не освобождается с delete; таким образом, вы теряете 32 байта памяти за вызов.

Как уже говорилось ранее, мой совет - просто использовать std::string и забыть об этих проблемах; Ваша функция становится такой простой:

std::string cardToString(const CARD& c)
{
    if(c.r >= 13 || c.r < 0 || c.s >= 4 || c.s < 0)
        return "(invalid card)";

    return std::string(RANKS[c.r]) + " of " + SUITS[c.s];
}

И вам больше не нужно беспокоиться об утечках памяти и ее распределении.

<ч />

Для справки / значения: если вызывающей стороне не нужно использовать ссылку для изменения объекта, хранящегося в векторе, я настоятельно рекомендую передавать его по значению. Падение производительности незначительно: два int с вместо одного указателя означают 8 против 4 байтов на большинстве 32-битных архитектур, и 8 байтов против 8 байтов на большинстве 64-битных машин (а также доступ к полям с помощью указателя требует небольших затрат) .

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

Затем, если у вас возникнут проблемы с производительностью, вы профилируете свое приложение, чтобы найти узкие места и оптимизировать эти критические точки.

1 голос
/ 06 апреля 2011

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

Вам нужно возвращать по значению, а не по ссылке (то есть CARD STACK::peek() { ... }).

...