4

I need to send a char array to ostream. Say I have the following print function:

Version 1:

void print(ostream &out, const char *str, unsigned len)
{
    out << string(str,len);
}

Version 2:

void print(ostream &out, const char *str, unsigned len)
{
    out.write(str,len);
}

Both versions above work to a certain extent. Version 1 looks less efficient because it will create an extra string object (causing memory allocation and data copying).

However Version 2 eliminates formatting possibilities. In the following example Version 1 works great (meaning that io manipulator successfully sets width to 10 and applies it to the next output field) :

out << setw(10);
print(out,s,slen);

Is there a way to keep functionality as in V1, but without paying extra for allocation/memcopy?

  • Both version are wrong (not taking a ostream&) –  Feb 18 '15 at 21:04
  • And as usual: Be not(!) concerned about optimizations unless you have a performance problem or a flawed algorithm. –  Feb 18 '15 at 21:14
  • I fixed typo in my example. Thanks for pointing out. Yes it should be ostream&. – Dmitriy Kumshayev Feb 18 '15 at 21:25
  • Does your string contain NUL bytes or isn't guaranteed to be NUL-terminated? If the answer to both questions is “no”, simply use `os << str`. – 5gon12eder Feb 18 '15 at 21:31
  • It is not guaranteed to be null-terminated. – Dmitriy Kumshayev Feb 18 '15 at 21:32
  • First, if the cost of `std::string(str,len)` is significant in any way then I would question whether it is a good idea to print that string at all, except possibly if this is only going to a data file. Second, I would be wary of _other_ inefficiencies that might crop up in any alternative technique. – David K Feb 18 '15 at 21:41
  • @DieterLücking ostreams are slow enough as it is, it seems reasonable to ask how to avoid an extra heap allocation and free which would be associated with a std::string (if the data is too big for SSO) – M.M Feb 18 '15 at 21:53

2 Answers2

3

There's no easy or reasonable way to do this.

The underlying issue is that operator<<(basic_ostream<charT, ...>&, basic_string<charT, ...>) is defined as behaving equivalent to operator<<(basic_ostream<charT, ...>&, const charT*), which calculates the number of characters to write via basic_ostream<charT, ...>::traits_type::length(str). There's no possibility of passing in a length with this interface.

If you can re-write it to take char* instead of const char*, you can temporarily set one of the characters to NULL before invoking the formatted output operator, and then reset it to it's original value after.

There was a proposal to add basic_string_view, which would do what you're looking for, but it wasn't included in C++14.

Collin Dauphinee
  • 13,664
  • 1
  • 40
  • 71
0

You could use a boost::iterator_range to stop the copying, as in:

out << boost::iterator_range<const char*>(str, str + len);

I don't think you can affect the formatting, as that is based in the type being inserted into the stream.

Nevin
  • 4,595
  • 18
  • 24