17

I have a class that I would like to store a static std::string that is either truly const or effectively const via a getter.

I've tried a couple direct approaches
1.

const static std::string foo = "bar";

2.

const extern std::string foo; //defined at the bottom of the header like so 
...//remaining code in header
};  //close header class declaration
std::string MyClass::foo = "bar"
/#endif // MYCLASS_H

I've also tried

3.

protected:
    static std::string foo;
public:
    static std::string getFoo() { return foo; }

These approaches fail for these reasons respectively:

  1. error: in-class initialization of static data member const string MyClass::foo of non-literal type
  2. storage class specified for foo -- it doesn't seem to like combining extern with const or static
  3. many 'undefined reference to' errors generated by other parts of my code and even the return line of the getter function

The reason I would like to have the declaration within the header rather than source file. This is a class that will be extended and all its other functions are pure virtual so I currently have no other reason than these variables to have a source file.

So how can this be done?

Manos Nikolaidis
  • 21,608
  • 12
  • 74
  • 82
user1854496
  • 622
  • 1
  • 8
  • 22
  • See http://stackoverflow.com/questions/1563897/c-static-constant-string-class-member for a related question, with an answer involving `constexpr` that utilizes C++11: http://stackoverflow.com/a/24341128/368896 – Dan Nissenbaum Aug 17 '14 at 14:53

2 Answers2

18

One method would be to define a method that has a static variable inside of it.

For example:

class YourClass
{
public:

    // Other stuff...

    const std::string& GetString()
    {
        // Initialize the static variable
        static std::string foo("bar");
        return foo;
    }

    // Other stuff...
};

This would only initialize the static string once and each call to the function will return a constant reference to the variable. Useful for your purpose.

Chris Cooper
  • 431
  • 3
  • 13
  • 2
    Clever, just to reassure myself I called this method in a for loop that iterates 2^32 times and there doesn't seem to be a memory leak. I do like billz point about just putting these vars in another namespace, but ultimately this was the answer to my question (I did have to add static to function declaration). Thanks! – user1854496 Aug 01 '13 at 01:35
  • Now to just automagically do the same thing for my gigantic map of vectorized strings... haha! – kayleeFrye_onDeck May 29 '18 at 23:15
14

You can only initialize a static const value in the constructor for integer types, not other types.

Put the declaration in the header:

const static std::string foo;

And put the definition in a .cpp file.

const std::string classname::foo = "bar";

If the initialization is in the header file then each file that includes header file will have a definition of the static member. There will be linker errors as the code to initialize the variable will be defined in multiple .cpp files.

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
  • 1
    He said in his question that he didn't want an implementation file though. – Chris Cooper Aug 01 '13 at 01:05
  • @ChrisCooper I noticed that, but I don't think that can be done. – Yu Hao Aug 01 '13 at 01:08
  • 1
    Oh... I initialized `const std::string` in a header for a project I'm working on. I wasn't getting linker errors... have this changed for C++11 - or am I missing something? – thomthom Jun 25 '14 at 20:28
  • Then probably you're including that file only once. – ikku100 Jun 19 '15 at 11:51
  • [Perhaps he was dictating it.](https://www.youtube.com/watch?v=ZlIz0q8aWpA) More seriously @thomthom your testimony may be interesting, but we can't tell anything without more details about your platform, compiler, etc. – Stéphane Gourichon Feb 21 '17 at 14:07