Page 1 of 1

Debug class

Posted: Mon May 31, 2010 4:30 pm
by short
edit: thanks to xeno for pointing out the vsnprintf function to me, and X abstract X for pointing out the =operator and copy constructor to me.

Code: Select all

/*
 *  Debug.h
 *  XCODE SFML_ENGINE
 *
 *  Created by Benjamin Adamson on 5/31/10.
 *  Copyright 2010 Oregon State University. All rights reserved.
 *
 */

#define dbg Debug::get_Instance()

#include <string>
#include <fstream>
#include <assert.h>
#include <stdio.h>

#ifndef _DEBUG_H_
#define _DEBUG_H_
class Debug
{
private:
	Debug(const Debug& d);	 // copy constructor needs to be private as well.
	Debug();
	~Debug();
	
	// member variables
	const static unsigned int m_sizebuffer = 1028;
	std::ofstream m_file;
	bool m_fileopened;
	char m_buffer[m_sizebuffer];
	va_list m_vl;
	
	//=operator needs to be private
	Debug& operator=(const Debug &rhs)
	{
	}
	
public:
	
	static inline Debug &get_Instance()
	{
		static Debug instance;
		return instance;
	}
	void open_file(const std::string& filename);
	void print(const std::string& fmt, ...);
};

#endif // End include guard.

Code: Select all

/*
 *  Debug.cpp
 *  XCODE SFML_ENGINE
 *
 *  Created by Benjamin Adamson on 5/31/10.
 *  Copyright 2010 Oregon State University. All rights reserved.
 *
 */

#ifndef _DEBUG_H_
#include "Debug.h"
#endif
Debug::Debug()
{
}

Debug::~Debug()
{
	if(m_fileopened)
	{
		m_file.close();
	}
	
}

void Debug::open_file(const std::string& filename)
{
	// file cannot already be opened.
	assert(!m_fileopened);
	
	m_file.clear(); // clear contents of debug file.
	m_file.open(filename.c_str());
	
	if(m_file.is_open() )
	{
		m_fileopened = true;
		dbg.print("Debug: successfully loaded file '%s'.\n", filename.c_str() );
	}
	else 
	{
		// file failed to open
		dbg.print("Debug: failed to open file '%s'.\n", filename.c_str() );
	}

}

/*
 WARNING: Should only accept c-style strings only. If output is ever cryptic double check 
 that we are not passing c++ Strings instead of char*, do not know how to differentiate if
 fmt is a c-style string (char*) or a C++ String.
 */
void Debug::print(const std::string& fmt, ...)
{
	// cannot print unless a file is opened.
	assert(m_fileopened);
	
    va_start(m_vl, fmt);
    vsnprintf(m_buffer, m_sizebuffer, fmt.c_str(), m_vl);
    va_end(m_vl);
    m_file << m_buffer;
    m_file.flush();
}
Hey guys, I decided that my old debug class wasn't good enough so I looked into how printf worked and discovered variadic functions. This is my first time using them, but I was hoping I could get some feedback.

Re: Debug class

Posted: Mon May 31, 2010 10:04 pm
by Xeno
I believe that when using variadic functions there must be at least one other parameter to the function, however you could change your dbg.print to act like printf by making the first argument a string which holds placeholders such as %s, then you can use vsnprintf to automagically replace the placeholders with the arguments.

Unfortunately since vsnprintf is a C style function, you'd need to use a char * as a buffer instead of a std::string, which kinda goes against the C++ style you're using.

An example will probably make it more clear:

Code: Select all


void Debug::print(const std::string& fmt, ...)
{
    char buffer[256];
    va_start(m_vi, fmt);
    vsnprintf(buffer, 256, fmt.c_str(), m_vi);
    va_end(m_vi);
    m_file << buffer;
    m_file.flush();
}

Then your example would work like:

Code: Select all


dbg.print("loading %s ....", mapname->c_str());


Re: Debug class

Posted: Mon May 31, 2010 11:17 pm
by X Abstract X
Since you asked for any ideas I'll just post my logger class, I have no idea what a variadic function is. Mine writes to the console but obviously it can be switched to write to a text file. I'm not sure but I think you might want to make sure you declare a private copy constructor and private assignment operator for the class you have right now.

Code: Select all

#ifndef Logger_H
#define Logger_H

#include <sstream>
#include <iostream>
#include <iomanip>

class Logger {
public:
    Logger() {}
    ~Logger() {}

    template <typename Type>
    Logger& operator<<(const Type& output) {
        std::stringstream stream;
        
        stream << std::setprecision(16) << output;
        
        std::cout << stream.str();

        return(*this);
    }
};

#endif

Re: Debug class

Posted: Tue Jun 01, 2010 2:26 am
by short

Code: Select all

Debug(const Debug& d);    // copy constructor needs to be private as well.

Code: Select all

//=operator needs to be private
   Debug& operator=(const Debug &rhs)
   {
   }
Ok I added these to my header, I understand declaring =operator as private being necessary. What I don't know is why Debug() being private is not enough. If I do not declare a constructor with a constant reference of type itself as a parameter will the compiler automatically generate one? I was under the assumption the only constructor the compiler automatically created for the user was the default Debug() (no parameters). Am I wrong?

To be more clear, when I first posted this code I had already declared Debug() as private.

Also, thanks a bunch for helping me out. I edited the first post with some slight changes to your post, :)

Re: Debug class

Posted: Tue Jun 01, 2010 2:29 am
by short
X Abstract X wrote:, I have no idea what a variadic function is.
The wikipedia: http://en.wikipedia.org/wiki/Variadic_function

Basically it's how printf can have an undetermined amount of parameters, and now my debug class :)

Re: Debug class

Posted: Tue Jun 01, 2010 2:13 pm
by X Abstract X
Hey you don't have to put the empty body of the assignment operator. And yes, copy constructors are automatically generated so you gotta make it private in this case. Just for future reference, you have to be careful with these default copy constructors because sometimes you MUST write your own. Look up deep vs. shallow copy for a better description than I could give.

Re: Debug class

Posted: Wed Jun 02, 2010 10:52 am
by short
X Abstract X wrote:Hey you don't have to put the empty body of the assignment operator. And yes, copy constructors are automatically generated so you gotta make it private in this case. Just for future reference, you have to be careful with these default copy constructors because sometimes you MUST write your own. Look up deep vs. shallow copy for a better description than I could give.
Nah I understand shallow vs deep, I just wasn't aware the compiler generated "2" default constructors.