Fundamentally, the implementation looks something like this (ignoring the fact that both the streams and the string are templates):
std::istream& operator>> (std::istream& in, std::string& value) {
std::istream::sentry cerberos(in);
if (cerberos) {
value.erase();
std::istreambuf_iterator<char> it(in), end;
if (it != end) {
std::ctype<char> const& ctype(std::use_facet<std::ctype<char> >(in.getloc()));
std::back_insert_iterator<std::string> to(value);
std::streamsize n(0), width(in.width()? in.width(): std::string::max_size());
for (; it != end && n != width && !ctype.is(std::ctype_base::space, *it); ++it, ++to) {
*to = *it;
}
}
}
else {
in.setstate(std::ios_base::failbit);
}
return in;
}
A reasonable implementation would probably use an algorithm which would process the content of the stream buffer's buffer segment-wise, e.g., to avoid the repeated checks and calls to is()
(although for the std::ctype<char>
it is really just applying a mask to an element of an array). In any case, the input operator wouldn't faff about allocating memory: a typical case "not my job".