Странно работает cin.get() после обработки ctrl+c

87
08 января 2022, 07:30

Суть программы в том, что пользователь вводит строку, которая посимвольно считывается и выводится на экран.
Реализована обработка ctrl+c, в результате которой пользователь выбирает, завершить ли программу. Если он хочет продолжить работу, то выводится строка "Продолжение ввода...", и функция close_handler(int sig) завершается. Функция cin.get() ожидает ввода, следовательно в потоке нет мусорных символов, но ввод происходит неправильно

Вопрос: почему после обработки ctrl+c данные не считываются правильным образом?

Пример правильной работы:
ввод: abcde
вывод: abcde

Пример неправильной работы:
ввод: ctrl+c
вывод: Вы уверены, что хотите выйти? Введите YES, чтобы завершить программу
ввод: no
вывод: Продолжение ввода...
ввод: abcde
вывод: de

Ожидаемое поведение:
ввод: ctrl+c
вывод: Вы уверены, что хотите выйти? Введите YES, чтобы завершить программу
ввод: no
вывод: Продолжение ввода...
ввод: abcde
вывод: abcde

#include <iostream>
#include <signal.h>
using namespace std;
void print_str()
{
  cout << "Введите строку: " << endl << endl;
  string str;
  char c = cin.get();
  while (c != '\n')
  {
    str += c;
    c = cin.get();
  }
  cout << str << endl;
}
void close_handler(int sig){
    cout << "Вы уверены, что хотите выйти? Введите YES, чтобы завершить программу" << endl;
    string ans;
    char c = cin.get();
    while (c != '\n')
    {
      ans += c;
      c = cin.get();
    }
    if (ans == "YES")
      exit(0);
    else
      cout << "Продолжение ввода..." << endl;
}
int main() {
  signal(SIGINT, close_handler);
  print_str();
  return 0;
}

Ссылка на код: https://repl.it/@DmitriiNiechipo/stackoverflow-question-0

Answer 1

С точки зрения С++ в обработчике сигнала нельзя работать ни с одним объектом со статическим временем хранения кроме объектов типа std::atomic. Это включает в том числе объекты стандартных потоков std::cin и std::cout. В противном случае это UB.

Также в обработчике сигнала нельзя пользоваться функциями стандартной библиотеки окромя следующих:

std::abort()
std::_Exit()
std::quick_exit()
std::signal() // только для того же сигнала

В С++17 этот список немного расширили, но принципиально ничего не поменялось. Так что вводом-выводом пользоваться всё равно будет нельзя.

Другими словами, всё что можно сделать в обработчике сигнала — это установить какой-либо флаг std::atomic и/или завершить программу. В конкретных ОС можно сделать немного больше, но ограничения всё равно довольно строгие.

См. Подробности на cppreference.

READ ALSO
Ассемблер зациклился

Ассемблер зациклился

Есть задание "Образовать строку из исходной, повторив 1-й и элемент 1 раз, 2-й элемент 2 раз, 3 и элемент – 3 раза и тд" на с++ с ассемблерными вставками

103
Принципы ООП. Интерфейс

Принципы ООП. Интерфейс

Пишу класс для работы с матрицамиУказатель и кол-во строк и столбцов сокрыто, это понятно

95