1

I'm working on making a game in C++. I have declared a Constant namespace used for global values that I need access to throughout the program. In there I have an ofstream for debugging purposes (yeah, I know it's not "constant" but it fits best there), which outputs only when it feels like it. I was able to make a small program demonstrating the problem. I apologize for it being spread across 4 files, but it is important, I promise.

main.cpp:

// Include necessary files
#include "test.h"
#include "constants.h"
#include <fstream>
using namespace std;

int main(int argc, char* argv[])
{
    // Start of program
    Constant::outstream.open("test.txt");

    // ...
    // Do stuff

    // Output debugging info
    Test test;
    test.print("Test", Constant::outstream);

    // ...
    // Do other stuff

    // End of program
    Constant::outstream.close();

    return 0;
}

constants.h:

#ifndef _CONSTANTS_H
#define _CONSTANTS_H

#include <fstream>

namespace Constant
{
    static ofstream outstream;
}

#endif

test.h:

#ifndef _TEST_H
#define _TEST_H

#include <string>
#include <fstream>
#include "constants.h"

class Test
{
public:
    void print(string str, ofstream& out);
};

#endif

test.cpp:

#include "test.h"
using namespace std;

void Test::print(string str, ofstream& out)
{
    out << "out: " <<  str << endl << flush; // Works
    Constant::outstream << "Constant::outstream: " << str << endl << flush; // Doesn't
}

In the test.cpp file, the out << ... line works as it should, while the Constant::outsream << ... line doesn't do anything even though I'm passing Constant::outstream as the out parameter! I don't see any reason why these two lines should be in any way different.

Before posting this, I tried putting test.cpp's code in test.h, just to have less files for the question, and was amazed to see it work. If I copy-paste the Test::print() function into test.h (whether inside or out of the class Test { ... }), then both output commands work correctly. the problem only occurs if Test::print()'s implementation is in a separate file.

It seems like any references to Constant::outstream simply don't work in class cpp files (no compile error, just nothing happens). It works in main.cpp and in class header files, but any class cpp file it seems not to. Unfortunately, this is a big program I'm writing so pretty much every class has its own cpp implementation file, and that's really the one place I need to use this ofstream. Does anyone know the reason for this?

Thanks in advance,
Doug

DougParker
  • 11
  • 2
  • Short answer, don't define variables in header files. Each cpp that includes the file gets a different variable. – Retired Ninja Apr 20 '14 at 05:17
  • Have you tried changing `static ofstream outstream;` to `extern ofstream outstream;` and then declare it inside your main file (be that main.cpp or test.cpp) .. ?? – txtechhelp Apr 20 '14 at 05:18
  • possible duplicate of [How do I share a variable between source files in C? With \`extern\`, but how?](http://stackoverflow.com/questions/1433204/how-do-i-share-a-variable-between-source-files-in-c-with-extern-but-how) – Retired Ninja Apr 20 '14 at 05:21
  • @txtechhelp: Changing `static` to `extern` gives me an "Unresolved external symbol" error. What exactly do you mean by "declare it inside your main file". Isn't in already declared in constants.h? – DougParker Apr 20 '14 at 05:35
  • See the answer @RetiredNinja posted; you've only defined it in your `constants.h` file, you now must declare it in your main.cpp or test.cpp file by putting `ofstream Constant::outstream;` somewhere in the file (usually after your `#include` statements) – txtechhelp Apr 20 '14 at 05:39
  • Ok, that seems to have taken care of it (when he posted that I was trying to put it in the main function, not outside of it). Why did it not throw any kind of compile error to begin with? Why was the `extern` needed at all? I thought putting it in a namespace allowed access without needing the `extern` statement. – DougParker Apr 20 '14 at 05:53
  • http://www.csee.umbc.edu/courses/undergraduate/202/spring07/Lectures/ChangSynopses/modules/m05-scope/slides.php?print <- this link has some useful info on the differences of lifetime and scope. Explaining (fully) why you need `extern` (to include why your original use of `static` was implied) will get into a comment discussion. I suggest going over the answer from the other comment as well as this link to get a better grasp on scope/lifetime and post a new question if there's any more confusion :) – txtechhelp Apr 20 '14 at 06:24

1 Answers1

0

Constant::outstream has internal linkage, thus a separate instance is created for each translation unit. In short, Constant::outstream in test.cpp and main.cpp are two different variables.

§3.5.2 A name having namespace scope (3.3.6) has internal linkage if it is the name of — a variable, function or function template that is explicitly declared static; or,

On the other hand, static class members would be visible throughout the program. So, if you would write

struct Constant
{
    static ofstream outstream;
}

instead of

namespace Constant
{
    static ofstream outstream;
}

it would work.

However, note that the class must have external linkage; e.g. you should not put in in anonymous namespace.

Blaz Bratanic
  • 2,279
  • 12
  • 17