Question

Ok, reformulated and consolidated from C++ Process terminated with status 3 confusion to a single file with minimum code, replacing my 'log' references with 'cout', printing to console instead of to file. I ran it through code::blocks compiler and got a different error, but for the same line ['log' was not declared in this scope]. It just closes the program with 'status 3' when I have the classes in their own files.

I've run into the scope error before, fixed it on my own, and thought I understood it, but I guess not...

#include <iostream>
#include <string> // Doesn't complain if this is not present...
using namespace std;

//------------------------------------------------------------
class Logfile {
public:
    bool LACT; // Is log file active?
    string value; // Data to be entered

    Logfile();
    ~Logfile();

    void entry(string value); // Make an entry
};

Logfile::Logfile() { // Constructor
    LACT = true;
    cout << "OPENED\n"; 
}

Logfile::~Logfile() {
    cout << "CLOSED\n";
}

void Logfile::entry(string value) {
    if ( LACT ) cout << value << endl;
}

//--------------------------------------------------
class Engine { // Constructor contains only code for this class right now
public :
    Engine();
};

This line is where the compiler hangs and gives me the error:

Engine::Engine() {
    log.entry("Engine constructed"); // !Problem line!
}

Am I on the right track thinking that the problem is that I am incorrectly calling a class method of an existing object from within a different class?

//--------------------------------------------------
int main()
{
    Logfile log;
    Engine engine;

    cout << "Hello world!" << endl;

    return 0;
}

When I '//' the line in question, everything runs fine and the console prints up the OPENED, Hello World!, CLOSED. Thank you for your patience and time, as I'm sure this is something far simpler - and novice - than it appears to be to me.

--

My initial purpose for asking this question was (now I realize) to get a globally declared object accessible from any *.cpp file in a multi-file program. I just found this answer: http://www.cplusplus.com/forum/beginner/3848/, in case this might be helpful to anyone else with a similar problem.

Was it helpful?

Solution

log and engine are totally separate. Neither has access to the other inherently.

If you want engine to be able to access an instance of Logfile, you could for example pass it into engine via a setter or via Engine's constructor:

Engine::Engine(Logfile& log) {
    log.entry("Engine constructed");
}

There are alternatives where you can have a global instance of Logfile (outside the scope of main). Generally global variables are a bad idea; variables' lifetimes should be reduced to the smallest scope possible. However, a logfile might qualify as a reasonable exception to this rule.


To explain a little further, you could use a singleton for the logfile. Using singletons is a highly contentious issue; just search for singletons or double-checked locking and you'll find ample discussions on the perils.

However, things have become a good bit safer with the advent of C++11. The new standard guarantees that initialization of a local static object is threadsafe. This allows us to do something like the following:

class Logfile {
public:
    static Logfile& instance();
    void entry(const string& value) { cout << value << '\n'; }
private:
    Logfile() { cout << "OPENED\n"; }
    ~Logfile() { cout << "CLOSED\n"; }
};

Logfile& Logfile::instance() {
    static Logfile log_file;
    return log_file;
}

Note that the constructor is now private. The only way to get a Logfile is via the instance() function, and since it has a local static Logfile, there will only ever be that one instance.

You can then use it inside Engine() like:

Engine::Engine() {
    Logfile::instance().entry("Engine constructed");
}

You still need to be careful here though. For example, at this point in time, VC2012 still hasn't implemented the threadsafe initialization of local statics as required by C++11.

OTHER TIPS

You need to let Engine class know where is log object. So you need to modify your code a bit to:

class Engine { // Core system, contains main loop
public :
    Engine(Logfile& log);

private:
    Logfile& log_;
};

Engine::Engine(Logfile& log):log_(log)
{
    log_.entry("Engine constructed");
}

Now you call it from main:

int main(int argc, char *argv[]) 
{
  Logfile log;
  Engine engine(log);
  return 0;
}

BTW: you are not really using string value; member in Logfile class, you can consider removing it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top