tags:

views:

105

answers:

5

I'm trying to write the contents of buf pointer to the file created by ofstream.

For some reason the file is empty, however the contents of buf is never empty... What am I doing wrong?

void DLog::Log(const char *fmt, ...)
{
    va_list varptr;

    va_start(varptr, fmt);

    int n = ::_vscprintf(fmt, varptr);
    char *buf = new char[n + 1];
    ::vsprintf(buf, fmt, varptr);

    va_end(varptr);

    if (!m_filename.empty())
    {

        std::ofstream ofstr(m_filename.c_str(), ios::out);

        ofstr << *buf; // contents of *buf are NEVER empty, however nothing is in file??

        ofstr.close();
    }


    delete [] buf;
}
A: 

You should check that the ofstream is open for writing after being created.

Visage
+4  A: 

Is your stream opened before writing on it ? Could be anything from not-enough disk space to unsufficient permissions.

Also you may have an error:

ofstr << *buf;

Should be something like:

ofstr << buf;

Since buf is a char*, *buf gives a char, not a char*.

This is where using std::string instead of raw buffers/pointers makes sense ;)

ereOn
+1  A: 

the error is in line

ofstr << *buf;

it should be

ofstr << buf;

MBZ
+2  A: 

You need to flush the ofstream before closing it. Try ofstr.flush(); before ofstr.close(); I had this error some time ago when I thought that closing the stream automatically flushes it but, as it turned out, it doesn't.

binW
I'm pretty sure it should, perhaps that was a bug in your implementation. But maybe I'm wrong, I"ll look.
GMan
@GMan: Did you look into it? Do tell us if you find any thing interesting
binW
@Adnan: Ah, yeah. It is indeed the case `close()` flushes the stream, and that `close()` is called by the destructor. §27.8.​1.2/3 describes the destructor of a `basic_filebuf`, and says that it calls `close()`. §27.8.​1.3/6 describes the closing procedure, which includes flushing the stream. And of course the file streams all have the same behavior as owning a `basic_filebuf` as a member, meaning when they destruct the `basic_filebuf` does, leading to the previous effects.
GMan
+2  A: 

Many problems can be solved by getting rid of the hairy stuff, like manual allocation management.

Never use new T[N] in your code: instead use std::vector<T> v(N);. Simply this alone might solve your problem, because the pointer stuff isn't in the way:

void DLog::Log(const char *fmt, ...)
{
    va_list varptr;
    va_start(varptr, fmt);

    int n = ::_vscprintf(fmt, varptr);
    std::vector<char> buf(n + 1);

    ::vsprintf(&buf[0], fmt, varptr);

    va_end(varptr);

    if (!m_filename.empty())
    {
        std::ofstream ofstr(m_filename.c_str(), ios::out);
        if (!ofstr) 
        {
            // didn't open, do some error reporting here
        }

        // copy each character to the stream
        std::copy(buf.begin(), buf.end(), std::ostream_iterator<char>(ofstr));

        // no need to close, it's done automatically
    }

    // no need to remember to delete
}

Much easier to read and maintain. Note even better would be a std::string buf(n + 1);, then you could just do ofstr << buf;. Sadly, std::string isn't currently required to store its elements contiguously, like std::vector. This means the line with &buf[0] isn't guaranteed to work. That said, I doubt you'll find an implementation where it wouldn't work. Still, it's arguably better to maintain guaranteed behavior.

I do suspect the issue was you dereferencing the pointer, though.

GMan