views:

154

answers:

3

I've developed a 'custom' cout, so that I can display text to console and also print it to a log file. This cout class is passed a different integer on initialization, with the integer representing the verbosity level of the message. If the current verbosity level is greater then or equal to the verbosity level of the message, the message should print.

The problem is, I have messages printing even when the current verbosity level is too low. I went ahead and debugged it, expecting to find the problem. Instead, I found multiple scenarios where my if statements are not working as expected.

The statement if(ilralevel_passed <= ilralevel_set) will sometimes proceed even if ilralevel_set is LESS then ilralevel_passed. You can see this behavior in the following picture (my apologizes for using Twitpic) http://twitpic.com/1xtx4g/full. Notice how ilralevel_set is equal to zero, and ilralevel_passed is equal to one. Yet, the if statement has returned true and is now moving forward to pass the line to cout.

I've never seen this type of behavior before and I'm not exactly sure how to proceed debugging it. I'm not able to isolate the behavior either -- it only occurs in certain parts of my program. Any suggestions are appreciated as always.

//  Here is an example use of the function:
//  ilra_status << setfill('0') << setw(2) << dispatchtime.tm_sec << endl;
//  ilra_warning << "Dispatch time (seconds): " << mktime(&dispatchtime) << endl;

//  Here is the 'custom' cout function:
    #ifndef ILRA_H_
    #define ILRA_H_

    // System libraries
    #include <iostream>
    #include <ostream>
    #include <sstream>
    #include <iomanip>

    // Definitions
    #define ilra_talk ilra(__FUNCTION__,0)
    #define ilra_update ilra(__FUNCTION__,0)
    #define ilra_error ilra(__FUNCTION__,1)
    #define ilra_warning ilra(__FUNCTION__,2)
    #define ilra_status ilra(__FUNCTION__,3)

    // Statics
    static int ilralevel_set = 0;
    static int ilralevel_passed;

    // Classes
    class ilra
    {
    public:
        // constructor / destructor
        ilra(const std::string &funcName, int toset)
        {
            ilralevel_passed = toset;
        }
        ~ilra(){};

        // enable / disable irla functions
        static void ilra_verbose_level(int toset){
            ilralevel_set = toset;
        }

        // output
        template <class T>
        ilra &operator<<(const T &v)
        {
            if(ilralevel_passed <= ilralevel_set)
                std::cout << v;
            return *this;
        }

        ilra &operator<<(std::ostream&(*f)(std::ostream&))
        {
            if(ilralevel_passed <= ilralevel_set)
                std::cout << *f;
            return *this;
        }

    };  // end of the class

    #endif /* ILRA_H_ */
+5  A: 

You should not be defining static variables in a header file like this:

static int ilralevel_set = 0;
static int ilralevel_passed;

I don't know what you think those definitions do, but they probably don't do what you want.

To declare in the class:

struct A {
   static int ilralevel;
};

You then need to define in one .cpp source file:

int A::ilralevel = 0;
anon
How else can I define them as static variables? You cannot define them within the class (it was actually another answer here on SO that led me to define them in the header file)
BSchlinker
@BSchlinker I don't really understand what you are doing with them, but you can certainly define them in the class.
anon
@Neil - no, you can't. You can declare them. In the case of integrals you can initialize them. You can't define them; not within a class declaration.
Noah Roberts
@Noah You are right. I have updated my answer - cannot update the comment. I'm sure this will resolve all the OP's problems.
anon
@Noah What is incorrect? If you don't like my answer, post one of your own or edit mine.
anon
@BSchlinker - in that same question another poster explains the enum {} workaround. Enum values can never be considered variables by the compiler so they end up always resolving to constant expressions, as opposed to static int variables that can be considered as either.
Noah Roberts
@Neil - my browser hadn't updated to include my last comment so I thought it was gone.
Noah Roberts
+1  A: 

Just a guess .. you're getting different copies of your static globals in different compilation units. fx, route.cpp has it's own copy of ilralevel_passed and ilralevel_set, plus an inlined copy of irla::operator<<. Move ilralevel_passed to a member variable of irla, and ilralevel_set to a static const, and see if that helps.

eduffy
+6  A: 

When you define a static variable outside a class, you're defining a separate variable for each source file into which you include the header -- changing the value in one doesn't affect the value of the variable with the same name in another file.

What you almost certainly want is to have

int ilralevel_set = 0;
int ilralevel_passed;

In one file where you're defining your object, and:

extern int ilralevel_set;
extern int ilralevel_passed;

in the header. Alternatively, it looks like you could move it all inside the class:

class ilra { 
    int passed_level;
    int set_level;
public:
    ilra(int toset) : passed_level(toset), set_level(0) {}

    verbose_level(int toset) { set_level = toset; }
    // ...
};
Jerry Coffin
Moving the integers inside of the class will make it impossible for my static functions to use them. Since I do not create an object and call the functions in the class directly, this is a requirement. If I was to create an object, I would need to constantly create it for each individual object.
BSchlinker
@BSchlinker: if you don't create an object, why do you use a class at all? For a case like that, you should probably just have functions (and variables) in a namespace.
Jerry Coffin
I try to prevent using global variables (which was the only method I knew for storing a variable between two separate functions). I'm also not very familiar with the usage of namespaces.See: http://stackoverflow.com/questions/3035582/static-variables-in-overloaded-functions
BSchlinker
@BSchlinker: assuming the variables are only accessed from/by your functions, you don't need to declare them in the header at all. Just define them in the implementation, declare them in the header, and you're good. The problem is arising now because you're defining them in the class definition, so they're inline functions, which will access the variable locally. Normal functions that are just declared in the header will access the variable where they're defined.
Jerry Coffin
@Jerry: I am currently defining them within the class definition? They are outside of the bounds of the class brackets though -- within the main header file itself. Isn't this 'declaring them in the header'?
BSchlinker
@BSchlinker: You're defining the *functions* in the class definition, which makes them inline functions.
Jerry Coffin
@Jerry Your solution worked, although I'm still confused about your previous comment within here. From your comment on Jun 18th "assuming the variables are only accessed from/by your functions, you don't need to declare them in the header at all. Just define them in the implementation, declare them in the header, and you're good". You say I do not need to declare them in the header, then instruct me to declare them in the header.
BSchlinker
@BSchlinker: Sorry -- I meant you leave the variables strictly in the implementation file. You implement the functions in the same file, and the header contains only declarations of the functions.
Jerry Coffin