1

I have heard several times, that one should avoid plain writes to std::cout. (Is this correct?) However, I did not find good examples of how to achieve this. What I came up with so far is this:

#include <iostream>

class Logger {

    std::ostream os;

    auto RdBuffer( bool const decision ) { return decision ? std::cout.rdbuf() : nullptr; }

    public:
    explicit Logger( bool const use_cout = true ) : os( RdBuffer( use_cout ) ) {}
    void Print() {
        os << "Ptinting" << std::endl;
    }
};

It allows me to write to std::cout if wanted, or stays silent otherwise. It seems to work, but I'm not sure this is the correct approach. What worries me in particular is the initialization with the nullptr and the consecutive writing to it in case the bool is set to false.

Is this going in the right direction? I'm particular interested in modern C++ ways of achieving this. So C++11 or newer answers are greatly appreciated.

Edit: Corrected typo in code.

SamVanDonut
  • 361
  • 2
  • 14
  • 2
    I think what you mean is that it is often considered bad practice to hardcode `std::cout` when actually you want to be flexible with respect to what stream to write. I have the feeling that you are making things more complicated than necessary. Just make it `void Print(std::ostream& out = std::cout)` and you are fine – 463035818_is_not_an_ai Feb 03 '21 at 13:32
  • The message was do not write `std::cout << "XYZ"` directly (= plain) in your code, because if you then want to e.g. silence output for testing (or whatever reason) you have to mess with `std::cout`. Better encapsulate it (like I tried) then you can just adjust your encapsulate rather than the global `std::cout` – SamVanDonut Feb 03 '21 at 13:32
  • Having said this, assuming your code does what you want, this question is basically asking for best practice and is opinion-based – 463035818_is_not_an_ai Feb 03 '21 at 13:33
  • The question is whether what I did is best practice and in particular whether the provided code is bug free (or in any other sense "dangerous")" See the remark on the `nullptr`. – SamVanDonut Feb 03 '21 at 13:34
  • yes that `nullptr` looks fishy. As I already said, imho you are making it far too complicated, but thats just my opinion. What works "best" depends on your specific needs – 463035818_is_not_an_ai Feb 03 '21 at 13:35
  • btw you arent actually calling the method `RdBuffer`. is this a typo? `RdBuffer` vs `Buffer` ? – 463035818_is_not_an_ai Feb 03 '21 at 13:37
  • You can make a no-op stream in C++ https://stackoverflow.com/q/11826554/10147399 – Aykhan Hagverdili Feb 03 '21 at 13:44

1 Answers1

4

I have heard several times, that one should avoid plain writes to std::cout. Is this correct?

No. It is accepted practice to write output to the standard output stream - unless you're in some embedded setting, or using an exotic OS where output is handled very differently.

The operating system and other processes will expect output to be written to that stream, or to whatever it represents (e.g. the standard output file handle on Unix-like systems).

What I came up with so far is this [piece of code here]

Well,

  1. There are several popular logging libraries for C++. Here's a question about that over at SoftwareRecs.SX. No need to re-invenet the wheel if what you want is to do logging.
  2. As @largest_prime_is_463035818 suggests in their comment, it's often good enough to just pass around an std::ostream and write to that. And when you want to not write anywhere - that's possible too; read these SO questions:

Having said all this - there are some cases in which you might legitimately want to have std::cout itself be redirected to print somewhere else. I don't think that's covered by the standard, though.
Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93
einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • It's fine if a stream shares the same buffer as `std::cout`. But passing a `nullptr` is probably not OK. You can make a no-op streambuf in C++ as shown here https://stackoverflow.com/q/11826554/10147399 – Aykhan Hagverdili Feb 03 '21 at 13:46
  • @AyxanHaqverdili: Wouldn't this comment be more relevant at the question I linked to? Or the answer there passing nullptr? Anyway, will edit. – einpoklum Feb 03 '21 at 14:04
  • Thanks a lot. The key-word "no-op" would have never come to me. That's why my search results were so crappy. – SamVanDonut Feb 03 '21 at 14:59
  • @einpoklum code in this question also passes `nullptr` to `std::ostream`. That's why I added my comment here. – Aykhan Hagverdili Feb 03 '21 at 18:38
  • Although, looking at the standard, passing nullptr maybe OK. I am not sure. The constructor calls `basic_ios::init` with that pointer, which sets badbit if the pointer is null. It's not often you see a null-check in the standard library :D – Aykhan Hagverdili Feb 03 '21 at 18:44
  • @AyxanHaqverdili: Ok, but, again - you're commenting in the wrong place my friend... – einpoklum Feb 03 '21 at 20:11