I have a strange issue where ostringstream is empty even though I insert an output to it.
Here is my code:
//logger.h
#include <string>
#include <iostream>
#include <sstream>
using std::string;
class BasicLogger {
public:
BasicLogger(const string name);
BasicLogger(const BasicLogger& basicLogger);
~BasicLogger();
template<class T>
BasicLogger& operator<<(const T &msg){
std::cout << "msg is: " << msg << std::endl;
mBuf << msg;
std::cout << "mBuf is: " << mBuf.str() << std::endl;
return *this;
}
private:
string mName;
std::ostringstream mBuf;
};
class Logger {
public:
Logger();
~Logger();
BasicLogger info();
BasicLogger error();
private:
BasicLogger mInfoLogger;
BasicLogger mErrorLogger;
};
//logger.cpp
#include "logger.h"
BasicLogger::BasicLogger(const string name):
mName(name) { }
BasicLogger::BasicLogger(const BasicLogger& otherLogger) {
this->mName = otherLogger.mName;
this->mBuf << otherLogger.mBuf.rdbuf();
}
BasicLogger::~BasicLogger() { }
Logger::Logger():
mInfoLogger("[INFO]"),
mErrorLogger("[ERROR]") {}
Logger::~Logger() {};
BasicLogger Logger::info() {
return mInfoLogger;
}
BasicLogger Logger::error() {
return mErrorLogger;
}
//main.cpp
#include "logger.h"
int main() {
Logger logger;
logger.info() << "Hellooo";
}
The output is
msg is: Hellooo
mBuf is:
While #BoPersson already gave you the solution, I would like to explain what happened here, and why your output is empty, even though you are adding to ostringstream on the line just before you display its content.
I think when you attempted to return mInfoLogger by value, the compiler complained about not being able to return it because copy constructor was deleted. The reason it was deleted because ostringstream member you have is non-copyable.
So you provided custom copy constructor and attempted to copy the stream this way:
this->mBuf << otherLogger.mBuf.rdbuf();
Only this does not copy anything as your rdbuf is empty and instead sets failbit on
The failbit
The streambuf overload of basic_ostream::operator<< if the function
inserts no characters.
http://en.cppreference.com/w/cpp/io/ios_base/iostate
If you were to check your message insertion like this:
if (!(mBuf << msg))
std::cout << "Not Inserted" << std::endl;
You would see Not Inserted message printed. There are many ways to make it print the desired message. For example making sure your rdbuf buffer is not empty or by resetting the failbit before you reuse the mBuf, something like mBuf.clear(); or simply by returning the reference to mInfoLogger (and mErrorLogger). Then you can safely get rid of your copy constructor.
Related
How to build a custom string inside what() function of exception class and return it? The following code does not work but presents what I want to achieve:
class divide_by_zero : public exception {
public:
divide_by_zero(int a) : a(a) {}
const char * what() noexcept {
stringstream ss;
ss << "Division " << a << " by zero!";
return ss.str().c_str();
}
private:
int a;
};
How to build a custom string inside what() function of exception class and return it?
Don't do that. It won't work.
Instead, build the custom string inside the constructor, store the string in a member, and return a pointer to the data owned by the member in what.
Technically, you can delay building the string until the first call to what. The primarily important thing is to store the string in a member rather than a local variable, and to not invalidate the returned pointer. Such delay is unnecessary complexity however, it is simpler to build the string in the constructor.
Your local stringstream is being destroyed too early as it's only local.
Cache the message result with the exception object.
#include <iostream>
#include <stdexcept>
#include <sstream>
#include <string>
using std::cout;
using std::exception;
using std::stringstream;
using std::string;
class divide_by_zero : public exception {
public:
divide_by_zero(int aa) : a{aa} {}
const char * what() const noexcept override {
if (msg.empty()) {
stringstream ss;
ss << "Division " << a << " by zero!";
msg = ss.str();
}
return msg.c_str();
}
private:
int a;
mutable string msg;
};
int main() {
try {
throw divide_by_zero(75);
} catch(exception const& ex) {
cout << "Caught exception " << ex.what() << "\n";
}
}
UPDATE, or use eerorika's recommendation:
#include <iostream>
#include <stdexcept>
#include <sstream>
#include <string>
using std::cout;
using std::exception;
using std::stringstream;
using std::string;
class divide_by_zero : public exception {
public:
divide_by_zero(int a) : msg{make_msg(a)} {}
char const* what() const noexcept override {
return msg.c_str();
}
private:
string msg;
static string make_msg(int a) {
stringstream ss;
ss << "Division " << a << " by zero!";
return ss.str();
}
};
int main() {
try {
throw divide_by_zero(75);
} catch(exception const& ex) {
cout << "Caught exception " << ex.what() << "\n";
}
}
You can format and store that string in the constructor and return it later on:
#include <cstdio>
#include <exception>
class divide_by_zero : public std::exception {
public:
divide_by_zero(int const a) {
std::sprintf(buff, formatStr, a);
}
const char * what() const noexcept override {
return buff;
}
private:
static constexpr auto& formatStr = "Division %d by zero!";
char buff[sizeof(formatStr) + 20];
};
This does no dynamic allocation, which is better in the case of exception handling.
I'm using CRTP design pattern to implement logging mechanism for my project. Base CRTP class looks like this:
#include <fstream>
#include <memory>
#include <mutex>
#include <iostream>
#include <sstream>
template <typename LogPolicy>
class Logger
{
public:
template <typename... Args>
void operator()(Args... args)
{
loggingMutex.lock();
putTime();
print_impl(args...);
}
void setMaxLogFileSize(unsigned long maxLogFileSizeArg)
{
//if (dynamic_cast<FileLogPolicy *>(policy.get()))
// policy->setMaxLogFileSize(maxLogFileSizeArg);
}
~Logger()
{
print_impl(END_OF_LOGGING);
}
protected:
std::stringstream buffer;
std::mutex loggingMutex;
std::string d_time;
private:
static constexpr auto END_OF_LOGGING = "***END OF LOGGING***";
void putTime()
{
time_t raw_time;
time(&raw_time);
std::string localTime = ctime(&raw_time);
localTime.erase(std::remove(localTime.begin(), localTime.end(), '\n'), localTime.end());
buffer << localTime;
}
template <typename First, typename... Rest>
void print_impl(First first, Rest... rest)
{
buffer << " " << first;
print_impl(rest...);
}
void print_impl()
{
static_cast<LogPolicy*>(this)->write(buffer.str());
buffer.str("");
}
};
One of the concrete logging class is logging to file, which looks like this:
#include "Logger.hpp"
class FileLogPolicy : public Logger<FileLogPolicy>
{
public:
FileLogPolicy(std::string fileName) : logFile(new std::ofstream)
{
logFile->open(fileName, std::ofstream::out | std::ofstream::binary);
if (logFile->is_open())
{
std::cout << "Opening stream with addr " << (logFile.get()) << std::endl;
}
}
void write(const std::string content)
{
std::cout << "Writing stream with addr " << (logFile.get()) << std::endl;
(*logFile) << " " << content << std::endl;
loggingMutex.unlock();
}
virtual ~FileLogPolicy()
{
}
private:
std::unique_ptr<std::ofstream> logFile; //Pointer to logging stream
static const char *const S_FILE_NAME; //File name used to store logging
size_t d_maxLogFileSize; //File max size used to store logging
};
Basically I create object of policy class and would like to log stuff, depending on the policy chosen. So for example I create logger like this:
FileLogPolicy log("log.txt");
In this case it should use Logger to save logs to file, by calling static_cast<LogPolicy*>(this)->write(buffer.str()). Apparently calling write function works fine but stream object is changing to null. How is that possible if FileLogPolicy destructor has not been called yet? When I change logFile to be normal pointer all works well. I don't get it where is the difference.
~Logger()
{
print_impl(END_OF_LOGGING);
}
this code runs after the descendend class has been destroyed.
void print_impl()
{
static_cast<LogPolicy*>(this)->write(buffer.str());
buffer.str("");
}
it then casts this to be a pointer to a class that this is no longer.
The unique ptr is gone, and even accessing the member is UB.
I have created a program in C++ for a class, and one of the requirements is to output a string when certain parts of the program have been called. For most of these I have simply assigned a string to a member variable and then outputted that variable. I wanted to know is it possible for me to assign the string in a destructor and then output that string? When I try it, it outputs nothing.
ie:
Class
private:
string output;
~Class {
output = "destructor has fired!";
}
int main(){
cout << class.message;
}
This is pseudocode so please ignore syntax mistakes/missing pieces.
It certainly is possible to output a message in the destructor, to know that it has fired, and one way to do it is this...
#include <iostream>
#include <string>
using namespace std;
class C{
string output; // by default private
public:
C(){}
~C() { cout << output << endl; }
void setString(const string& s) {
output = s;
}
};
int main()
{
{
C s;
s.setString("Destructor has fired");
}
return 0;
}
If I understand your question right, this is what you are expected to do. Note: no member variable, direct calls to std::cout.
#include <iostream>
#include <string>
using namespace std;
class C{
public:
C() {
cout << "C ctor" << endl;
}
~C() {
cout << "C dtor" << endl;
}
};
int main()
{
{
C s;
}
return 0;
}
I show you the code directly.
#include <iostream>
#include <stdio.h>
class A {
public:
A(const std::string& name){
std::string aname = "HAHA_" + name;
std::cout << aname << std::endl;
}
~A(){
std::cout << "Done." << std::endl;
}
};
int main() {
size_t len = 5;
char szTmp[30] ={0};
snprintf(szTmp,sizeof(szTmp),"Getlist_V2_%zd",len);
A a(std::string(szTmp));
return 0;
}
The expected results are as follows:
HAHA_Getlist_V2_5
Done.
But It outputs nothing at all. When I replace A a(std::string(szTmp)); with
A a(szTmp); ,erverything is ok. It confused me for a long time.
A a(std::string(szTmp));
This is a function declaration, believe it or not! So, no A is constructed.
Instead, write this:
A a{std::string(szTmp)};
Or, since an implicit conversion to std::string exists, either of the following will suffice:
A a{szTmp};
A a(szTmp);
I've a working logger class, which outputs some text into a richtextbox (Win32, C++).
Problem is, i always end up using it like this:
stringstream ss;
ss << someInt << someString;
debugLogger.log(ss.str());
instead, it would be much more convenient to use it like a stream as in:
debugLogger << someInt << someString;
Is there a better way than forwarding everything to an internal stringstream instance? If'd do this, when would i need to flush?
You need to implement operator << appropriately for your class. The general pattern looks like this:
template <typename T>
logger& operator <<(logger& log, T const& value) {
log.your_stringstream << value;
return log;
}
Notice that this deals with (non-const) references since the operation modifies your logger. Also notice that you need to return the log parameter in order for chaining to work:
log << 1 << 2 << endl;
// is the same as:
((log << 1) << 2) << endl;
If the innermost operation didn't return the current log instance, all other operations would either fail at compile-time (wrong method signature) or would be swallowed at run-time.
Overloading the insertion operator<< is not the way to go. You will have to add overloads for all the endl or any other user defined functions.
The way to go is to define your own streambuf, and to bind it into a stream. Then, you just have to use the stream.
Here are a few simple examples:
Logging In C++ by Petru Marginean, DDJ Sept 05th 2007
Rutger E.W. van Beusekom's logstream class, check also the .hpp alongside with this file
As Luc Hermitte noted, there is "Logging In C++" article which describes very neat approach to solve this problem. In a nutshell, given you have a function like the following:
void LogFunction(const std::string& str) {
// write to socket, file, console, e.t.c
std::cout << str << std::endl;
}
it is possible to write a wrapper to use it in std::cout like way:
#include <sstream>
#include <functional>
#define LOG(loggingFuntion) \
Log(loggingFuntion).GetStream()
class Log {
using LogFunctionType = std::function<void(const std::string&)>;
public:
explicit Log(LogFunctionType logFunction) : m_logFunction(std::move(logFunction)) { }
std::ostringstream& GetStream() { return m_stringStream; }
~Log() { m_logFunction(m_stringStream.str()); }
private:
std::ostringstream m_stringStream;
LogFunctionType m_logFunction;
};
int main() {
LOG(LogFunction) << "some string " << 5 << " smth";
}
(online demo)
Also, there is very nice solution provided by Stewart.
An elegant solution that also solves the flushing issues is the following:
#include <string>
#include <memory>
#include <sstream>
#include <iostream>
class Logger
{
using Stream = std::ostringstream;
using Buffer_p = std::unique_ptr<Stream, std::function<void(Stream*)>>;
public:
void log(const std::string& cmd) {
std::cout << "INFO: " << cmd << std::endl;
}
Buffer_p log() {
return Buffer_p(new Stream, [&](Stream* st) {
log(st->str());
});
}
};
#define LOG(instance) *(instance.log())
int main()
{
Logger logger;
LOG(logger) << "e.g. Log a number: " << 3;
return 0;
}
In the Logger class, override the << operator.
Click Here to know how to implement the << operator.
You can also avoid the logging statements inside the code
using Aspect Oriented programming.