16

I am reading Bjarne Stroustrup's "Programming Principles and Practice Using C++" (second edition). On page 660-661, the writers define a function as follows:

istream& read_word(istream& is, char* buffer, int max)
    // read at most max-1 characters from is into buffer
{
    is.width(max);    // read at most max-1 characters in the next >>
    is >> buffer;     // read whitespace-terminated word,
                      // add zero after the last character read into buffer
    return is;
}

Later in int main(), the function is called as read_word(cin,s,max); where cin is std::cin, max is an int, and s is a char array of size max.

I don't understand how is >> buffer; works. In particular, that line gives an error when I tried to run the code:

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

There is no user-defined operator>> or further explanation on that line (except the comment) in the book.

I wonder if we can use things like is >> buffer; in any meaningful way? If so, how does it work? Or is this an error in the book?


Update: I'm using Visual Studio 2022. I found that the code runs successfully with C++14/17, but not with C++20. The results are similar for clang and gcc.

2
  • 1
    Code looks good to me. godbolt.org/z/hjz8YjcKe If you add a minimal reproducible example and the complete and unadulterated build error message from the output tab maybe someone will see something I missed. Commented Jul 13, 2022 at 5:32
  • 3
    Ha! I didn't even think to try C++ 20. Didn't expect anyone using Visual Studio would be using it. Last I checked, it defaulted (yes defaulted. Not defecated, you stupid spell checker) to C++14, so I defaulted to 14. Maybe I'm being compiler racist, but I'm not as bad as the spell checker which clearly seems to think Visual studio is caca. Commented Jul 13, 2022 at 6:08

2 Answers 2

22

The std::basic_istream::operator >> overload that takes a char* argument (overload #2 in this cppreference page) was removed in C++20. This change will, no doubt, break huge amounts of existing code, including examples given by Bjarne Stroustrup himself!

The C++20 replacement, taking a char (&s)[N] argument instead, seems (to me, at least) far less accessible. One way to adapt to this change is to rewrite the read_word function as a template, when you would no longer require the explicit max argument and the call to is.width():

template <size_t N>
std::istream& read_word(std::istream& is, char (&buffer)[N])
{
    is >> buffer;
    return is;
}

However, as mentioned in Alan Birtles' answer, you should really be moving away from raw char[] arrays and start using std::string, instead.

Sign up to request clarification or add additional context in comments.

7 Comments

How much of that existing code was correctly setting width to prevent buffer overflows though? I'm not aware of a single time I've used this overload in my professional career either?
@Alan Agreed. The 'old' operator is dangerous and I can sort of understand why the Standard Committee removed it. (Possibly the C++ 'analogue' of the horrible gets function?)
Worth noting that The most recent edition of Principles and Practices is pretty old now. About time for a new rev that covers C++17 and 20 (and maybe 23).
@Quimby there have been a few breaking changes in new c++ revisions, e.g the removal of auto_ptr
@Quimby I'm pretty sure that there are other changes made at C++20 that break some existing code. Probably also true for other Standard releases, too.
|
9

The stream operator taking a raw char pointer has been replaced with one taking a fixed sized char array in c++20. The simplest solution is to use std::string instead.

To use an array your code would be something like:

template <size_t N>
istream& read_word(istream& is, char (&buffer)[N], int max)
    // read at most max-1 characters from is into buffer
{
    is.width(max);    // read at most max-1 characters in the next >>
    is >> buffer;     // read whitespace-terminated word,
                      // add zero after the last character read into buffer
    return is;
}

Note that this will now read at most N-1 characters, if N and max are the same then you can omit max and the width call.

2 Comments

Should max also be of type size_t?
@Chris streamsize would be the most appropriate en.cppreference.com/w/cpp/io/ios_base/width though strangely setw takes an int en.cppreference.com/w/cpp/io/manip/setw

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.