3

I am taking a course on C++ and I have been asked to compute the area of a circle by using getline. I was advised to refrain from using cin unless it is really necessary.

Below is my code..

#include <iostream>
#include <string>

int main()
{
    std::string question ("Enter the radius: ");
    std::string s_radius;
    std::cout << question;

    getline(std::cin, s_radius);

    const double PI = 3.14159;
    double n_radius = std::stod(s_radius);
    double area = PI * n_radius * n_radius;

    std::cout << "The area of the circle = " << area << std::endl;

    return 0;
}

Is it really necessary to go through the process of accepting a string as input and convert it to a numeral to perform the calculation?

Alok Y
  • 59
  • 5
  • 1
    how you get the input and the calculations you do with the input are orthogonal concerns. Using `cin` is often easier, sometimes its easier to use `getline`, depends on the format of the input. However, "refrain from using cin unless it is really necessary" I never heard before – 463035818_is_not_a_number Sep 04 '18 at 11:45
  • 1
    @Carcigenicate you can ignore errors whether you use `std::cin >>` or `getline`, that doesnt really make them different – 463035818_is_not_a_number Sep 04 '18 at 11:47
  • There must have been some misunderstanding somewhere - you're still using `std::cin`. (It's not easy to read from standard input without using `std::cin`.) If the requirement is that you read the input with `getline`, there is no way to get around the conversion. – molbdnilo Sep 04 '18 at 12:04
  • On a tangent: a *numeral* is a symbol - that is, a string of some kind - and not a number. "12" and "XII" are numerals that both represent the number twelve. Literal numerical values, like `3.14159` and `0`, are numerals. The values of `PI` and `n_radius`, on the other hand, are not. – molbdnilo Sep 04 '18 at 12:12
  • typically to avoid pitfalls like this : [Why does std::getline() skip input after a formatted extraction?](https://stackoverflow.com/questions/21567291/why-does-stdgetline-skip-input-after-a-formatted-extraction) – Sander De Dycker Sep 04 '18 at 12:23
  • If you don't want to use std::string then you can simply go with std::cin. In your case, you're already advised to use getline. getline actually get line from stream into string until the delimitation character ('\n') is found, so you have to use string to store the input. – sonulohani Sep 04 '18 at 12:40

2 Answers2

3

Is it really necessary to go through the process of accepting a string as input and convert it to a numeral to perform the calculation?

It isn't strictly necessary but it does enforce good habits. Let's assume you are going to ask for 2 numbers from the users and use something like

std::cout << "Enter first number: ";
std::cin >> first_number;
std::cout << "Enter second number: ";
std::cin >> second_number;

For the first number the user enters 123bob. operator>> is going to start reading it in and once it hits b it is going to stop and store 123 into first_number. Now the stream has bob still in it. When it asks for the second number since bob is still in the stream it will fail and second_number will get set to 0. Then the program will continue on and you will get garbage output because you accepted garbage input.

Now, if you read in as a std:string and then convert to what you want it makes it easier to catch these types of errors. getline(std::cin, some_string); would get all of 123bob out of the input buffer so you don't have to worry about having to clean it up. Then using stoi (or any of the stox functions) it will read the valid value of of it. The functions also have a second parameter which is a pointer to a size_t and if you pass it one it will store the position of the first unconverted character in the string and you can use that to tell if the entire input string is valid or not. So, if you had

std::string input;
std::cout << "Enter some number: ";
std::getline(std::cin, input);
std::size_t pos;
double number = std::stod(input, &pos);
if (pos == input.size())
    std::cout << "valid input\n";
else
    std::cout << "invalid input\n";

Then 1.23bob would cause invalid input to print where 1.23 cause valid input to print. You could even use this in a loop to make sure you get only valid input like

double number;
do
{   
    std::string input;
    std::cout << "Enter some number: ";
    std::getline(std::cin, input);
    std::size_t pos;
    number = std::stod(input, &pos);
    if (pos != input.size())
        std::cout << "invalid input\n";
    else
        break;
} while(true)

TL;DR: If you rely on the user to only input valid input eventually you are going to get burned. Reading in as a string and converting offers a consistent way to ensure that you are only getting good input from your user.

NathanOliver
  • 150,499
  • 26
  • 240
  • 331
0

I was advised to refrain from using cin unless it is really necessary.

First of all, there is a misunderstanding, because you are still using std::cin. I will interpret your question as using std::cin::operator >> vs getline(std::cin,...). Next I would rather suggest you the opposite: Use operator>> directly if you can and fall back to getline if you have to.

A very contrived example:

Imagine you have integers stored in a file in this (unnecessarily complex) format,

3123212
^-------- number of digits of the first number
 ^^^----- first number
    ^---- number of digits of the second number
     ^^-- second number

You cannot use a bare std::cin >> to read those numbers. Instead you need to read the whole line and then parse the numbers. However, even for this I would highly recommend to provide an overload for operator>>, something along the line of

struct NumbersReadFromStrangeFormat {
    std::vector<int> numbers;
};

std::isstream& operator>>(std::istream& in,NumbersReadFromStrangeFormat& num) {
    // use getline and parse the numbers from the string
    return in;
}

Such that you can again write:

NumbersReadFromStrangeFormat numbers;
std::cin >> numbers;

Conclusion: Overloading the operator>> is the idomatic way to read something from an input stream. "Using std::cin" or "using getline" are not really alternatives. "Refraining from using std::cin" must be a misunderstanding. If there is no overload of operator>> that already does what you need, you can write your own and nicely hide any getline or other parsing details.

463035818_is_not_a_number
  • 64,173
  • 8
  • 58
  • 126