Вопрос:

C ++ Векторные элементы заменяются последним вызовом push_back

c++ vector push-back

62 просмотра

2 ответа

23 Репутация автора

Так что у меня есть этот код в моей основной функции

if(mesType == 1) {
        cin.ignore();
        Message mes1;
        stack1.push(&mes1);
} else if(mesType == 2) {
        cin.ignore();
        MorseCodeMessage mes2;
        stack1.push(&mes2);
}

и вот функция

void MessageStack::push(Message *ms1) {
    messages.push_back(ms1);    
}

где сообщения

vector <Message*> messages;

Можете ли вы объяснить, почему все элементы в моем векторе сообщений заменяются тем, что я нажимаю последним?

Автор: Caleb lee Источник Размещён: 08.11.2017 10:35

Ответы (2)


1 плюс

30699 Репутация автора

Вы помещаете указатели на локальные переменные, что, скорее всего, приводит к неопределенному поведению; если локальный объект не вышел из области видимости, у вас есть возможность повторно нажать адрес одного и того же объекта (локальная переменная). Обратите внимание, что содержимое локальной переменной изменится, и все ранее отправленные адреса все еще будут указывать на один и тот же объект.

Автор: Stephan Lechner Размещён: 08.11.2017 10:41

1 плюс

365692 Репутация автора

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

Поскольку у вас явно есть полиморфные классы, которые являются производными Message, вам нужно динамически распределять их, newчтобы они оставались живыми, пока хранятся в векторе:

if(mesType == 1) {
    cin.ignore();
    Message *mes1 = new Message;
    stack1.push(mes1);
} else if(mesType == 2) {
    cin.ignore();
    MorseCodeMessage *mes2 = new MorseCodeMessage;
    stack1.push(mes2);
}

Не забудьте определить Messageс помощью виртуального деструктора, а затем вызывать deleteкаждый указатель, когда вы закончите использовать вектор или удаляете элементы из вектора. В противном случае у вас будут утечки памяти.

В C ++ 11 и более поздних версиях более безопасное решение - использовать std::unique_ptrвместо необработанных указателей:

std::vector<std::unique_ptr<Message>> messages;

void MessageStack::push(std::unique_ptr<Message> ms1) {
    messages.push_back(std::move(ms1));
}

...

if(mesType == 1) {
    cin.ignore();
    stack1.push(std::unique_ptr<Message>(new Message));
    // or, in C++14 and later:
    //stack1.push(std::make_unique<Message>());
} else if(mesType == 2) {
    cin.ignore();
    stack1.push(std::unique_ptr<Message>(new MorseCodeMessage));
    // or, in C++14 and later:
    //stack1.push(std::make_unique<MorseCodeMessage>());
}
Автор: Remy Lebeau Размещён: 08.11.2017 10:51
Вопросы из категории :
32x32