Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ std::ofstream class members

Tags:

c++

stdout

first time contributor, but I believe I've checked the past posts correctly and do not find a solution that works. I am using Visual Studio 2012...

Essentially, all I want to do is stream output to a log file owned by an object. I have no hang-ups about how precisely this should be achieved but nothing in the archives works.

As I understand it, this accepted solution ought to work:

#include <fstream>
// classA.h
class A {
private:
    std::ofstream * _logfile;
public:
    A(void);
    void dosomething(void) const;
}

and

// classA.cpp
#include classA.h
A::A(void) : _logfile(0) {
    std::ofstream output("logfile.txt",std::ofstream::app);
    _logfile = &output;
}

A::dosomething(void) {
    *_logfile << "Print something" << std::endl;
}

and

// main.cpp
int main() {
A a = new A();
a->dosomething();
}

This compiles ok but just hangs. Most probably, I guess, because output disappears at ctor end. What's a good robust way to achieve this functionality? Other StackOverflow suggestions read result in compiler errors...

Thanks, Chris

like image 952
loadsamates Avatar asked Apr 20 '26 23:04

loadsamates


2 Answers

The code has undefined behaviour as _logfile is a dangling pointer after A has been constructed because it is taking the address of output which is a local variable defined in the constructor of A: when A's constructor completes, output is destructed. _logfile is then dereferenced in do_something(), which is undefined behaviour and is the probable cause of the hang.

To solve, just use a std::ofstream member and make A non-copyable (as streams are not copyable, but are movable):

class A {
private:
    std::ofstream _logfile;
    A(const A&);
    A& operator=(const A&);
public:
    A() : _logfile("logfile.txt",std::ofstream::app) {}
    void dosomething()
    {
        _logfile << "Print something" << std::endl;
    }
};
like image 113
hmjd Avatar answered Apr 23 '26 14:04

hmjd


You have a pointer to an object on a stack, it will be deleted after the constructor is finished:

#include classA.h
A::A(void) : _logfile(0) {
    std::ofstream output("logfile.txt",std::ofstream::app);//it's on the stack
    _logfile = &output;//pointer to an object on the stack
}

A::dosomething(void) {
    *_logfile << "Print something" << std::endl;
}

better use:

std::ofstream _logfile;

and init it in the initialization list of the constructor:

A::A(void) : _logfile("logfile.txt",std::ofstream::app){}
like image 38
Kostia Avatar answered Apr 23 '26 13:04

Kostia



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!