Home > Software engineering >  Is there a clean way to instantiate a const std::string private member from a getenv call
Is there a clean way to instantiate a const std::string private member from a getenv call

Time:11-17

I have a class that needs to grab an environment variable and use it in various processing. It should be const. My understanding of constness is that it must be instantiated on initialization. So something like this would work

class C 
{
public:
  C() : idFromEnv(getenv("ENV")) {}

private:
  std::string idFromEnv;

};

But that isn't a safe way of doing it because an exception will be thrown if the string is null. I thought there might be a way of incorporating ternary operators to do this. Something like this, but this is really ugly:

class C
{
  public:
  C() : idFromEnv(getenv("ENV") ? getenv("ENV") : "UNKNOWN") 
  {
      std::cout << idFromEnv << "\n";
  }

  private:
  const std::string idFromEnv;
};

I'm not using that. Anyone have any more elegant suggestions?


Based on suggestions, I tried this. It does work. Not quite what I had in mind.

class C 
{
    public:
    
    inline const std::string getEnvString(const char *env) 
    {
        char* cStr = getenv(env);
        return(std::string(cStr ? cStr : "UNKNOWN"));
    }
    
    C() : idFromEnv(getEnvString("ENV"))
    {
        std::cout << idFromEnv << "\n";
    }
    
    private:
    const std::string idFromEnv;
};

CodePudding user response:

You might also consider using a default member initializer.

So instead of writing it in the constructor, you would add a default value for idFromEnv:

class C
{
public:
    C() = default;
private:
    std::string idFromEnv = getenv("ENV") ? getenv("ENV") : "UNKNOWN";;
};

CodePudding user response:

My understanding of constness is that it must be instantiated on initialization.

There is no const issues in the 1st example you present, so there is no need to initialize idFromEnv in the constructor's initialization list if you don't want to. You can assign it in the constructor's body instead, eg:

class C 
{
public:
  C()
  {
    char* cStr = getenv("ENV");
    idFromEnv = cStr ? cStr : "UNKNOWN";
  }

private:
  std::string idFromEnv;
};

But, if idFromEnv needs to be const, then yes, you have to initialize it in the constructor's initialization list instead. So using a helper function to wrap the extra getenv() handling is really your best option, eg:

std::string getenvstr(const char *env)
{
  char* cStr = getenv(env);
  return cStr ? cStr : "UNKNOWN";
}

class C 
{
public:
  C() : idFromEnv(getenvstr("ENV")) {}

private:
  const std::string idFromEnv;
};
  • Related