3

I am teaching C++ via Visual Studio and I would like to provide a portable, safe, modern System("pause") like function. Reading How to simulate “Press any key to continue?” is rather frustrating as not a single answer provides a portable / modern solution that works.


The common suggestion: std::cin.get(); generally just doesn't do it:

  • if std::cin was used before - it is skipped. So it needs to be called twice to pause once.
  • if written twice - and there was no input before - it will pause twice.
  • if input earlier was invalid all calls are skipped. std::cin.clear() before doesn't solve it.

std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

Is better than std::cin.get(); since calling std::cin.clear(); does in fact work for corrupted input (still causing a break).


Given that std::cin.ignore(...); is skipped in an unpredictable manner is a problem. Note that this is also true for std::getline(std::cin, dummy); and std::cin >> dummy; (and of course std::cin.get();.


Since std::cin doesn't provide a check to see if it was used (like a flag) I have to see if the pause statement is skipped. One solution could be to use std::getline() and look if the resulting std::string is empty. The problem:

  • user presses 'enter': the string is empty.

  • statement is skipped: the string is empty.

So this doesn't work. I can't see a way to implement this correctly without asking the user to input something other than enter.


I thought about this long and have one solution which is portable but hardware dependant: Messuring the time. typing in 'enter' takes considerably more time than beeing skipped. I say if the elapsed time is less than 20 microseconds I can assume it was skipped and ask for the second std::cin.ignore(...).

On my system the skipping never took more than 10 microseconds. The reaction time of humans will never exceed that - but this latency can be reduced when pressing 'enter' just before the function is called. In this quick case the lowest timeframe I got was 100 microseconds. So here's this implementation:

#include <iostream>
#include <limits>
#include <chrono>

void system_pause(unsigned max_keyboard_latency_hz = 50'000u) {
    std::cout << "press enter to continue . . . ";
    if (!std::cin.good()) {
        std::cin.clear();
    }
    auto t1 = std::chrono::high_resolution_clock::now();
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    auto t2 = std::chrono::high_resolution_clock::now();

    double delta_t = std::chrono::duration_cast<std::chrono::nanoseconds>(t2 - t1).count() / 1e9;
    if (delta_t < 1.0 / max_keyboard_latency_hz) {
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }
}

and max_keyboard_latency_hz is the value (in hertz) where the first std::cin.ignore(); is considered skipped, if executed quicker. It behaves correctly after: input, corrupted input and no input. The problem is the extreme case (immediately pressing enter before) which is hardware dependant (perfomance / input latency) alltough the flexible max_keyboard_latency_hz negates that a bit.


I would just like to know if there's a way to make a working System("pause"); like implementation which works for all three prior cases: input, no input and corrupted input. As far as my research goes there is no such solution so I will probably settle on my implementation (which is certainly not something to be happy about).

Stack Danny
  • 7,754
  • 2
  • 26
  • 55
  • 8
    [The best way is _to not do this_.](https://stackoverflow.com/a/36374595/560648) – Lightness Races in Orbit May 28 '19 at 13:21
  • 1
    @LightnessRacesinOrbit The only way to win is not to... pause? ;) – NathanOliver May 28 '19 at 13:24
  • 1
    @NathanOliver Exactly! Now, how about a nice game of "run your program from an already-open terminal if so desired"? – Lightness Races in Orbit May 28 '19 at 13:25
  • @LightnessRacesinOrbit I am fully aware of this. The Problem is teaching with Visual Studio, you have to use it. Putting breakpoint opening with Ctrl + F5 doesn't work if you send your executable to someone for them to open. And explainging them "you have to open cmd.exe, navigate to the Folder and open it from there" is not great for beginners. – Stack Danny May 28 '19 at 13:25
  • 10
    I disagree. Teaching how to use computers properly is _fantastic_ for beginners!! Get 'em while they're young... – Lightness Races in Orbit May 28 '19 at 13:25
  • 1
    @StackDanny beginners are going to have to learn to use the terminal. It is going to come up so making them familiair with from the beginning is a good option. – Tarick Welling May 28 '19 at 13:27
  • Yes, good argument. But still I would like to know if it's possible. Imagine you are starting and you want to show your console application to a friend - such a (working) function would be convenient to skip the terminal stuff. – Stack Danny May 28 '19 at 13:29
  • It can also be convenient to run red lights and drive down the pavement to avoid traffic ... until you kill someone. It would be great if we could stop this bad habit forming at the start, and you're in a wonderful position to be able to help do that. I do recognise however that this is off-topic to your question, so... – Lightness Races in Orbit May 28 '19 at 13:29
  • I touch on my reasons in the linked answer. – Lightness Races in Orbit May 28 '19 at 13:32
  • I should mention that your idea of timing the cin doesn't allow the user to press the "any" key early, because they know the prompt will come up. – Gem Taylor May 28 '19 at 13:34
  • A POSIX standard way to pause the process would be the SIGSTOP signal. Does windows support that? (although that is different from wait for input) – eerorika May 28 '19 at 13:35
  • @eerorika [Don't think so](https://stackoverflow.com/q/100480/560648) – Lightness Races in Orbit May 28 '19 at 13:36
  • 3
    None of the options are great. You either need to use something OS specific, or hack something together that will only work most of the time. For instance, with your final function there could be multiple newlines in the input buffer. If there is then you wont catch that. As other have said, just not pausing is a much easier option. It only takes a couple minutes to show someone how to open the command window / use the debugger and run the code, and that is a useful skill they can take with them. – NathanOliver May 28 '19 at 13:38
  • 7
    Teach the novices using Visual Studio to set a breakpoint at the end of main. Then teach them some of the basics of using a debugger. – Eljay May 28 '19 at 13:38
  • @NathanOliver but doesn't `ignore(std::numeric_limits::max(), '\n')` guarantee to hit all of the newlines? – Stack Danny May 28 '19 at 13:40
  • 2
    @StackDanny No. The second parameter is the character to stop at. So, it will ignore all of the characters in the stream until `std::numeric_limits::max()` or `'\n'` is reached (it will actually only go until `\n` since `max` disables the count check and will only stop when it finds the delimeter). So if your buffer has `\n\n\n\n` in it after the first ignore call it has `\n\n\n` still in it. – NathanOliver May 28 '19 at 13:42
  • I just thought I missed something but given that it appears that there is no real solution I will go for the breakpoint + explain terminal strategy. I just didn't know, but if that's the way to go than I gladly do. – Stack Danny May 28 '19 at 13:48
  • 3
    Treating streams as real-time input source is pretty much always a hack. They're streams! If you want a "GUI" like thing then make a GUI :P Or a cmd-line mimicry like with ncurses or kbhit... but then you're back to API-specific things _and_ you still are doing the evil thing! – Lightness Races in Orbit May 28 '19 at 13:55
  • 1
    @StackDanny And this is why VS comes with the a project option of keeping the window open when you run... – UKMonkey May 28 '19 at 14:07
  • @UKMonkey but it's only useful inside Visual Studio and not when running the executable externally. – Stack Danny May 28 '19 at 14:09
  • My preferred portable solution is `std::system("PAUSE");`. It has the great advantage of not working on Linux, so I don't have to deal with those stupid "press a key to continue" prompts. – melpomene May 28 '19 at 14:09
  • 2
    @StackDanny and that's the way it should be - if you want to keep the window open - then run it from a window - because as said already, you break the ability to chain otherwise. – UKMonkey May 28 '19 at 14:11
  • 1
    I have always thought that even if programs are initially developped in a IDE, they are supposed to be used outside of the IDE after a time. So I really *hate* seeing a `read`, `sleep` or anything else as last instruction in a program. Have you ever seen that in a real world program??? A break on the `return 0;` does same thing and does not clutter code. Please do not teach that to beginners. – Serge Ballesta May 28 '19 at 14:21
  • @SergeBallesta yes, you are of course right. I despite this, too. I was maybe a bit too scared going straight from a simple "hello world, Input something or not" program to the terminal, but it seems that I underestimated the severity. That even if I praise "don't do this officially" - it's bad practise. – Stack Danny May 28 '19 at 14:25
  • 1
    @StackDanny it's much easier to be taught good habits/practice from the start, than to try and unlearn bad ones! Even if you highlight that it's bad, the question (if I was a student) would be "then why are you teaching it to me?" – UKMonkey May 28 '19 at 14:34
  • @UKMonkey well I always had mixed feelings towards it, like it's a necessary evil. But I certainly have changed my mind now! – Stack Danny May 28 '19 at 14:41
  • 3
    Update to the current version of Visual Studio (2017), and the problem goes away. It now keeps the console window open for you, even when you run from within the IDE with the debugger attached. – Cody Gray - on strike May 28 '19 at 17:23
  • @CodyGray I didn't know, that's great. Thanks. – Stack Danny May 29 '19 at 07:14
  • the option is [Automatically close the console when debugging stops](https://developercommunity.visualstudio.com/content/problem/316364/1581-automatically-close-the-console-when-debuggin.html) which is enabled by default on VS2017 onwards. [Preventing console window from closing on Visual Studio C/C++ Console application](https://stackoverflow.com/a/54084067/995714) – phuclv Jun 12 '19 at 16:25

0 Answers0