web-dev-qa-db-fra.com

Existe-t-il une implémentation null std :: ostream en C ++ ou dans les bibliothèques?

Je recherche un std::ostream implémentation qui agit comme /dev/null. Il ignorerait simplement tout ce qui y est diffusé. Une telle chose existe-t-elle dans les bibliothèques standard ou Boost? Ou dois-je rouler le mien?

52
paperjam

Si vous avez boost, alors il y a une implémentation nulle ostream & istream disponible dans boost/iostreams/device/null.hpp. L'essentiel:

#include "boost/iostreams/stream.hpp"
#include "boost/iostreams/device/null.hpp"
...
boost::iostreams::stream< boost::iostreams::null_sink > nullOstream( ( boost::iostreams::null_sink() ) );
...
19
Ylisar

La solution la plus simple consiste simplement à utiliser un std::ofstream Non ouvert. Cela se traduira par un état d'erreur dans le flux, mais la plupart des éditeurs ne vérifieront pas cela; l'idiome habituel est de laisser la vérification à la fin, après la fermeture (ce qui le mettrait dans le code que vous avez écrit, où vous savez que le flux devrait être invalide).

Sinon, il est assez simple à implémenter: créez simplement un streambuf qui contient un petit tampon, et configurez-le dans overflow (toujours avec succès). Notez que ce sera plus lent que le fichier non ouvert, cependant; les différents opérateurs >> effectueront toujours la totalité de la conversion (ce qu'ils ne font pas si le flux a un état d'erreur).

ÉDITER:

class NulStreambuf : public std::streambuf
{
    char                dummyBuffer[ 64 ];
protected:
    virtual int         overflow( int c ) 
    {
        setp( dummyBuffer, dummyBuffer + sizeof( dummyBuffer ) );
        return (c == traits_type::eof()) ? '\0' : c;
    }
};

Il est habituel de fournir également une classe de commodité dérivée de istream ou ostream, qui contiendra une instance de ce tampon qu'il utilise. Quelque chose dans le sens de:

class NulOStream : private NulStreambuf, public std::ostream
{
public:
    NulOStream() : std::ostream( this ) {}
    NulStreambuf* rdbuf() const { return this; }
};

Ou vous pouvez simplement utiliser un std::ostream, En lui passant l'adresse du streambuf.

26
James Kanze

Si vous définissez badbit sur un flux, cela ne produira rien:

#include <iostream>

int main() {
    std::cout << "a\n";

    std::cout.setstate(std::ios_base::badbit);
    std::cout << "b\n";

    std::cout.clear();
    std::cout << "c\n";
}

Les sorties:

a
c
17
Maxim Egorushkin

Je sais que c'est un fil très ancien, mais je voudrais l'ajouter à tous ceux qui recherchent la même solution sans boost et la plus rapide.

J'ai combiné trois propositions différentes ci-dessus et une en écrivant directement dans/dev/null (cela implique donc le noyau.)

Étonnamment, le NullStream qui a obtenu le plus de votes a donné le pire.

Voici les résultats de 100 000 000 d'écritures:

a) /dev/null : 30 seconds
b) NullStream: 50 seconds
c) badbit    : 16 seconds (the winner in speed, but cannot test for errors!)
d) boost     : 25 seconds (the ultimate winner)

Voici le code de test

#include <iostream>
#include <fstream>
#include <time.h>
#include <boost/iostreams/stream.hpp>

class NullStream : public std::ostream {
    class NullBuffer : public std::streambuf {
    public:
        int overflow( int c ) { return c; }
    } m_nb;
public:
    NullStream() : std::ostream( &m_nb ) {}
};

int test( std::ostream& ofs, const char* who ) {
    const time_t t = time(NULL);
    for ( int i = 0 ; i < 1000000000 ; i++ )
        ofs << "Say the same" ;
    std::cout << who << ": " << time(NULL) - t << std::endl;
}

void devnull() {
    std::ofstream ofs;
    ofs.open( "/dev/null", std::ofstream::out | std::ofstream::app );
    test(ofs, __FUNCTION__);
    ofs.close();
}

void nullstream() {
    NullStream ofs;
    test(ofs, __FUNCTION__);
}

void badbit() {
    std::ofstream ofs;
    ofs.setstate(std::ios_base::badbit);
    test(ofs, __FUNCTION__);
}

void boostnull() {
    boost::iostreams::stream< boost::iostreams::null_sink > nullOstream( ( boost::iostreams::null_sink() ) );
    test(nullOstream, __FUNCTION__);
}

int main() {
    devnull();
    nullstream();
    badbit();
    boostnull();
    return 0;
}

MODIFIER

La solution la plus rapide - où nous utilisons le badbit - a un inconvénient. Si le programme vérifie si la sortie a été écrite avec succès - et je ne sais pas pourquoi le programme ne devrait pas faire cela - alors il échouera à cause de cette erreur. Par conséquent, le runner up - boost - est le gagnant.

8
Grzegorz

Pour moi, le moyen le plus simple serait:

#include <fstream>

std::ostream* out = &std::cout;

std::ostream* nullstream() {
    static std::ofstream os;
    if (!os.is_open())
        os.open("/dev/null", std::ofstream::out | std::ofstream::app);
    return &os;
}

int main() {
    *out << "Normal output\n";

    out = nullstream();
    *out << "Will not visible\n";

    out = &std::cout;
    *out << "Back again\n";

    return 0;
}

Ou utilisez l'indicateur 'badbit' au lieu de '/ dev/null' dans la fonction 'nullstream' comme décrit ci-dessus.

std::ostream* nullstream() {
    static std::ofstream os;
    static bool flag_set = false;
    if (!flag_set) {
        os.setstate(std::ios_base::badbit);
        flag_set = true;
    }
    return &os;
}
0
user1317490

Puisse cette solution surmonter le problème de performances sans utiliser boost:

#include <ostream>

class dev0_buffer : public std::streambuf
{
   //called usually for n-characters
   std::streamsize xsputn (const char* s, std::streamsize n) override { return n; }

   //may not required due it's not called anymore
   int overflow (int c)  override { return c; } 
} nirwana;

class dev0_stream : public std::ostream
{
   public:
    dev0_stream(): std::ostream(&nirwana){}
};
0
Karsten