2

I'm trying to initialize a static class member and having no luck. Here's a test:

file Test.h

#include <string>

class Test {

public:
    static void init(char*);

private:
    static std::string  *sp;

};

file Test.cpp

#include "Test.h"

// Initialize the class
void
Test::init(char *foo) {
    Test::sp = new std::string(foo);
}

int main(int argc, char** argv) {
    Test::init(argv[1]);  // call the class initializer
}

The linker fails with:

Undefined symbols for architecture x86_64:
  "Test::sp", referenced from:
      Test::init(char*) in Test-OK13Ld.o
ld: symbol(s) not found for architecture x86_64

In the real world, init() is going to do some real work to set the static member. Can someone point out the error?

Chap
  • 3,649
  • 2
  • 46
  • 84
  • `static std::string *sp;` is not difined. – user1810087 Jul 15 '13 at 04:00
  • also, why use a pointer to std::string? – billz Jul 15 '13 at 04:06
  • Well, I know what an undefined ref / unresolved extern is, so that link is fairly broad. @itwasntpete 's comment reminded me that all I have is a declaration. So apparently I need a definition in (but outside) the class definition. – Chap Jul 15 '13 at 04:06

2 Answers2

1

As the error message says, static std::string *sp; has to be defined somewhere since it's not associated with any instance of class Test.

Adding it to Test.cpp at global scope will fix the issue:

std::string *Test::sp = NULL;
greatwolf
  • 20,287
  • 13
  • 71
  • 105
1

This is a bit of an embarrassing "feature" of C++: you need to do some hand holding to make sure the linker can generate the symbols. You need to choose some cpp file, and make sure that no such handholding occurs for the same symbols in any other (otherwise the linker will fail when it encounters duplicate symbols). So you have to do another declaration of the static member variables for your class in the cpp file like this:

std::string * Test::sp; // or sp = NULL;
user268396
  • 11,576
  • 2
  • 31
  • 26
  • Ah -- the difference between declaration and definition. I never thought about exactly where those statics would live; I just imagined C++ would take care of things. It's worth mentioning (if this is true!) that the definition (or is it another declaration?) must be outside of any functions in the .cpp file. – Chap Jul 15 '13 at 04:16
  • That really *is* ugly! If written as an assignment statement, at what point is it executed? – Chap Jul 15 '13 at 04:19
  • Well that is where the term "static initialization order fiasco" rears its ugly head. Basically, before main but when exactly depends on all other `static` variables and you really, really don't want to depend on this. So don't do hairy stuff before `main` if you can avoid it (which is almost always). The only point of setting the pointer to `NULL` is that you can check if it has been set "properly" by your init function yet. – user268396 Jul 15 '13 at 04:24
  • Thanks. If you'd edit your answer to emphasize that the static member definition should be *outside* of any function in the .cpp, I'll give you the checkmark. (I know the compiler will bark otherwise, but it sure looks weird.) – Chap Jul 15 '13 at 04:32