2009-04-17 10 views
30

Czekam na tworzenie klasy rejestrowania, która ma członków, takich jak informacje, błąd itp., Które można konfigurowalne wyjście do konsoli, pliku lub donikąd.Wdrażam no-op std :: ostream

Dla zwiększenia efektywności chciałbym uniknąć narzutów związanych z formatowaniem wiadomości, które będą wyrzucane (tj. Wiadomości informacyjnych, gdy nie są uruchomione w trybie szczegółowym). Jeśli zaimplementuję niestandardowy std :: streambuf, który wyprowadza donikąd, wyobrażam sobie, że warstwa std :: ostream nadal będzie formatować. Czy ktoś może zaproponować sposób na naprawdę "zerowy" std :: ostream, który unika wykonywania jakiejkolwiek pracy na parametrach przekazywanych do niego z <<?

Dzięki.

+0

Nie martwię się. po prostu użyj strumienia pustego, jak pokazano przez Neila. klasa nie wymaga żadnej lepszej wydajności, ponieważ oczywiście jeśli nie masz zerowego celu, formatowanie * ma * do wykonania, więc oczywiście nie jest krytyczne. tylko moje 2 centy –

+0

hmm, ale wygląda na to, że jest przeznaczony jako "wynik debugowania"? jeden sposób widziałem jest tak: out() << a << b ...; i out() zwraca struct f {}; bez szablonu f const & operator << (f const i f_, T const) {return f_; }, a następnie sprawdź zwracane różne struktury w zależności od poziomu dziennika. lub tworzyć różne funkcje lub cokolwiek innego. –

Odpowiedz

4

Aby zapobiec wykonywaniu formatowania przez wywołania operator<<(), powinieneś znać typ strumienia podczas kompilacji. Można to zrobić za pomocą makr lub szablonów.

Mój roztwór szablonowy następuje.

class NullStream { 
public: 
    void setFile() { /* no-op */ } 
    template<typename TPrintable> 
    NullStream& operator<<(TPrintable const&) 
    { /* no-op */ } 
} 

template<class TErrorStream> // add TInfoStream etc 
class Logger { 
public: 
    TErrorStream& errorStream() { 
     return m_errorStream; 
    } 

private: 
    TErrorStream m_errorStream; 
}; 

//usage 
int main() { 
    Logger<std::ofstream> normal_logger; // does real output 
    normal_logger.errorStream().open("out.txt"); 
    normal_logger.errorStream() << "My age is " << 19; 

    Logger<NullStream> null_logger; // does zero output with zero overhead 
    null_logger.errorStream().open("out.txt"); // no-op 
    null_logger.errorStream() << "My age is " << 19; // no-op 
} 

Ponieważ musisz to zrobić podczas kompilacji, jest to oczywiście mało elastyczne.

Na przykład nie można wybrać poziomu rejestrowania w środowisku wykonawczym z pliku konfiguracyjnego.

+0

+1: proste, czyste, dobrze działa. Zwróć uwagę, że"NullStream s; s << expensive_function();" najprawdopodobniej nadal będzie oceniać metodę expensive_function(), szczególnie jeśli znajduje się ona w innym module. –

+3

Wspomnę również, że w przeciwieństwie do Neull's onullstream, twój NullStream nie może zostać przekazany do funkcji oczekującej ostream & or ostream * argumentu. –

+0

expensive_function() będzie _definitely_ być oceniane bez względu na to, gdzie mieszka. Nie ma sposobu, aby zaprzeczyć, że obce są makra i kompilacja warunkowa :) ... jeśli chodzi o Neila, nie sądzę, że spełnia on wymóg "zera formatowania" :) –

0

Prawdopodobnie potrzebujesz czegoś więcej niż tylko formatowanie tekstu i filtrowanie wiadomości. A co z wielowątkowością?

Zaimplementowałem synchronizację filtrowania i wielowątkowość jako odpowiedzialność oddzielnej klasy.

Jednak rejestrowanie to nie jest taki prosty problem, a zamiast tworzyć nowe, starałbym się korzystać z istniejących rozwiązań rejestrowania.

15

Błyskawiczny google wymyślił ten przykład, który może być przydatny. Nie oferuję żadnych gwarancji, poza tym, że kompiluje się i uruchamia :-)

+0

+1. Tak, domyślam się, że wywodzenie ze std :: basic_ostream <> jest konieczne, jeśli chcesz przekazać strumień "do niczego" do funkcji oczekującej parametru ostream & lub ostream * - sztuczka Iraimbilanji nie zadziała. –

+0

może zostać zaakceptowany jako "ostream *", a nie "ostream &", czy jest poprawny? – athos

0

Dlaczego nie skorzystać z istniejących rozwiązań logowania używanych przez miliony użytkowników? log4j, log4net, log4cxx .., aby wymienić tylko kilka ..

13

wszystkim, dzięki za udostępnienie kodu, po prostu zrobić test, a następnie metoda Neila będzie jeszcze zrobić formatowania łańcucha znaków, na przykład:

#include <streambuf> 
#include <ostream> 
#include <iostream> 
using namespace std; 


template <class cT, class traits = std::char_traits<cT> > 
class basic_nullbuf: public std::basic_streambuf<cT, traits> { 
    typename traits::int_type overflow(typename traits::int_type c) 
    { 
     return traits::not_eof(c); // indicate success 
    } 
}; 

template <class cT, class traits = std::char_traits<cT> > 
class basic_onullstream: public std::basic_ostream<cT, traits> { 
    public: 
     basic_onullstream(): 
     std::basic_ios<cT, traits>(&m_sbuf), 
     std::basic_ostream<cT, traits>(&m_sbuf) 
     { 
      init(&m_sbuf); 
     } 

    private: 
     basic_nullbuf<cT, traits> m_sbuf; 
}; 

typedef basic_onullstream<char> onullstream; 
typedef basic_onullstream<wchar_t> wonullstream; 

class MyClass 
{ 
    int a; 
    friend ostream& operator<< (ostream&, MyClass const&); 
}; 

ostream& operator<<(ostream& out,MyClass const& b) 
{ 
    std::cout<<"call format function!!"; 
    out << b.a; 
    return out; 
} 

int main() { 
    onullstream os; 
    MyClass obj; 
    os<<obj; 
} 

Uruchomienie tego programu, można zauważyć, że "ostream & operator < < (ostream & się, MyClass const & b)" zostanie wywołana. Zatem formatowanie na obiekcie będzie nadal wywoływane. Wciąż nie możemy uniknąć nadmiarowego formatowania wiadomości.

+0

Optymalizator AFAIK może usunąć kod, który jest uważany za bez skutków ubocznych. Ponieważ twoje wywołanie 'std :: cout <<" funkcja formatu wywołania !! '' ma efekty uboczne, wtedy optymalizator nie usunie tego. Jednak bez połączenia możliwe jest, że zostanie ono usunięte –

Powiązane problemy