Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't use std::cin with char* or char[] in C++20

Tags:

c++

c++20

It used to work: Reading from std::cin to a dynamically allocated char array - or to an array passed in as a parameter (see MCVE below).

#include <iostream>

void read (char str[256]) //or omit the # between the []'s -- no difference
{
    std::cin >> str; //error
}

int main ()
{
    char  s1 [256];
    char* s2 = new char[256];
    char  s3 [256];

    std::cin >> s1;   //OK
    std::cin >> s2;   //error
    read (s3);       

    return 0;
}

I believe the problem is a C++20 update called Fixing operator>>(basic_istream&, CharT*). Its purpose is to prevent std::cin from overflowing the string it's reading into, and cppreference.com does list new prototypes for std::istream's operator>> that now have CharT (&s)[N] , not CharT* s, as the argument taken.

Confirmation: this MCVE works with g++ 10 (which doesn't support this), and with Visual Studio using Default as the language flag; but using /std:c++latest, VS complains:

binary '>>': no operator found which takes a right-hand operand of type 'char *' (or there is no acceptable conversion) 

So I totally get what the compiler's complaining about. But how do I use std::cin with arrays passed in as parameters, or dynamic arrays?

(Also: how does C++ know, when it's ready to read, whether an array was created dynamically or statically? It's not supposed to be able to draw that distinction after declaration!)

like image 328
Topological Sort Avatar asked Jun 04 '20 12:06

Topological Sort


1 Answers

But how do I use cin with arrays passed in as parameters, or dynamic arrays?

Don't. If you have a char array, give it the char array like

void read (char (&str)[256]) // now we have a reference to an array, so we know its size
{
    std::cin >> str;
}

// or if we don't care about the size, we just want an array

template <std::size_t N>
void read (char (&str)[N]) // now we have a reference to an array, so we know its size
{
    std::cin >> str;
}

and if you have a dynamic size, use a std::string which still works with cin

void read (std::string& str)
{
    std::cin >> str;
}

(Also: how does C++ know, when it's ready to read, whether an array was created dynamically or statically? It's not supposed to be able to draw that distinction after declaration!)

It's not that it knows that its ready to read, it that it knows the size that it can read. When you give it a pointer, it just has to trust the pointer points to enough memory. If you give it an array, by passing the array by reference, then the compiler knows the size it can read as the size of an array is part of the type information, unlike a pointer. Don't confuse array's decaying into a pointer into arrays being a pointer. They are two different things.

like image 150
NathanOliver Avatar answered Sep 19 '22 15:09

NathanOliver