views:

109

answers:

3

For an application that uses a number of environment variables, is there some kind of a convention or "best practice" when it comes to grabbing environment variables and putting them into either a struct or a bunch of const's? Obviously, I want to fallback to a default value for each and every environment variable. Right now, using the following seems like a very messy way of doing it:

char* x;
const SOME_VARIABLE;
if (NULL == (x = getenv("SOME_VARIABLE")))
    SOME_VARIABLE = 5; // default value
else
    SOME_VARIABLE = x;

I could also write a function that wraps getenv to return a default value if an environment variable is empty, but I'm not sure if that's even the best way to do it. I could also do away with using const, but that doesn't seem like a good thing to do, either.

Any thoughts?

+8  A: 

How about:

std::string GetEnvironmentVariableOrDefault(const std::string& variable_name, 
                                            const std::string& default_value)
{
    const char* value = getenv(variable_name.c_str());
    return value ? value : default_value;
}

Used as:

const std::string some_variable = GetEnvironmentVariableOrDefault("SOME_VARIABLE", "5");
James McNellis
Seems like the simplest solution. Thanks.
dav
A: 

James McNellis has provided a great answer, but here is an alternate opinion:

I think getenv() returns the value of the environment variable at the time the program was started. If the environment variable gets changed after the program is started, getenv() would still return the old value. Based on that, an alternate approach may be to have a class to capture all the required environment variables as attributes. The class is populated at the start of the program, and provides only (const-qualified) accessor methods. That way the getenv() is called exactly once for each environment variable. On the negative side, the class takes up some space.

In the alternate approach, which does not use any space, getenv() is called whenever the value of any environment variable is required. It’s not that the getenv() call is expensive (actually I don’t’ know), but it carries a false assumption to the programmer that the latest value might be returned.

Also having a class may be useful to abstract if there is any dependency in using the environement variables, e.g.

if $OS = "SunOs" 
then 
    GCC="/bin/gcc" 
else 
    GCC="/usr/bin/gcc" 

(this is just an example though)

Now, a function who don’t care about $OS but needs only $GCC, can just refer to envClass->get("GCC");

Just a thought.

ArunSaha
Good point, although I don't plan on using these constants in *too* many places, so I probably won't have to call `getenv` too many times. A class for this seems a bit overkill IMO, as that's really just duplicating what `getenv` already does.
dav
A: 

I usually do this with a class that loads configuration settings (either from the environment or a configuration file). I instantiate a single global instance of it at startup. The program settings are a method or property of the configuration class object. It's simple and when you write code it's pretty clear what you intended:

if ( configuration.ExitOnFailure && IsError() )
   exit();
Jay