0

I have some following code. In order to limit call times of operator << to std::cout. I use an std::ostream outside forloop. But I get compile errors.

  • source code shows:
#include <iostream>

int square(int num) {

    std::ostream os;
    for (int i=0; i<10; i++) {
        os << "test: i," << std::endl;
    }
    std::cout << os;

    return 0;
}
  • error shows:
In file included from /opt/compiler-explorer/gcc-5.5.0/include/c++/5.5.0/iostream:39:0,
                 from <source>:2:
/opt/compiler-explorer/gcc-5.5.0/include/c++/5.5.0/ostream: In function 'int square(int)':
/opt/compiler-explorer/gcc-5.5.0/include/c++/5.5.0/ostream:384:7: error: 'std::basic_ostream<_CharT, _Traits>::basic_ostream() [with _CharT = char; _Traits = std::char_traits<char>]' is protected
       basic_ostream()
       ^
<source>:6:18: error: within this context
     std::ostream os;
                  ^
Compiler returned: 1

Does the smart code with efficiency exist?

Let me make my intension clear.

I don't want to call api and write date to std::cout by multiple times in a loop. I know that I can use a string buffer to receive data multiple times, and finally print to std::cout. But this also takes the cost of creating a string. Is there any directly use of the api or structure provided by <iostream> to write better code?

mariolu
  • 624
  • 8
  • 17
  • 1
    Personally, I would just use `cout << "test: i,\n"` in the for loop. Not sure if there is anything faster that you can do. You're working with a stream so that right there is going to be your bottleneck in performance. – NathanOliver May 18 '21 at 13:11
  • 1
    You mean `os << "test: " << i << "," << std::endl;` instead of `os << "test: i," << std::endl;`? – MikeCAT May 18 '21 at 13:12
  • 2
    You can't create a "bare" default `std::ostream`. – molbdnilo May 18 '21 at 13:14
  • @molbdnilo You can create an instance of `std::ostream` itself, you just have to give it a `std::streambuf` to write to. – Remy Lebeau May 18 '21 at 16:33

2 Answers2

0

I'm not sure about efficiency, but what you want to do looks like using std::stringstream.

#include <iostream>
#include <sstream>

int square(int num) {

    std::stringstream ss;
    for (int i=0; i<10; i++) {
        ss << "test: i," << std::endl;
    }
    std::cout << ss.str();

    return 0;
}
MikeCAT
  • 73,922
  • 11
  • 45
  • 70
  • 1
    FWIW, this is about as inefficient as you can get. First, your building a string buffer, so multiple allocations as it grows. Second, `str` returns by value so you have another allocation plus an `O(N)` copy. – NathanOliver May 18 '21 at 13:13
0

If you want efficiency, you there are a few things you could do.

If you want to keep using iostreams, you should take a look at std::ios_base::sync_with_stdio, it can make std::cout much faster, but you wouldn't be able to use C functions to read/write from streams. You also shouldn't use std::endl, as it forces a stream flush, use '\n' instead.

#include <iostream>

int square(int num) {
    for (int i=0; i<10; i++) {
        std::cout << "test: " << i << '\n';
    }
    return 0;
}

int main(){
    std::ios_base::sync_with_stdio(false);
    ...
}

You could also use an external library, fmt is amaizing for that.

#include <fmt/core.h>

int square(int num) {
    for (int i=0; i<10; i++) {
        fmt::print("test: {}\n", i);
    }
    return 0;
}
Kaldrr
  • 2,780
  • 8
  • 11