21

Possible Duplicate:
C++ static constant string (class member)
static const C++ class member initialized gives a duplicate symbol error when linking

My experience with C++ pre-dated the addition of the string class, so I'm starting over in some ways.

I'm defining my header file for my class and want to create a static constant for a url. I'm attempting this by doing as follows:

#include <string>
class MainController{
private:
    static const std::string SOME_URL;
}

const std::string MainController::SOME_URL = "www.google.com";

But this give me a duplicate definition during link.

How can I accomplish this?

Community
  • 1
  • 1
Thom
  • 14,013
  • 25
  • 105
  • 185
  • dup http://stackoverflow.com/questions/2888805/static-const-c-class-member-initialized-gives-a-duplicate-symbol-error-when-lin – David Nehme Sep 27 '11 at 15:03

4 Answers4

17

Move the

const std::string MainController::SOME_URL = "www.google.com";

to a cpp file. If you have it in a header, then every .cpp that includes it will have a copy and you will get the duplicate symbol error during the link.

David Nehme
  • 21,379
  • 8
  • 78
  • 117
  • 2
    I guess what I don't quite understand is that I have these within my header guards. This fixed the problem, I just don't understand why... – Thom Sep 27 '11 at 19:47
  • 4
    @Thom, the problem is not solved with the headers guards because each translation unit (cpp file) includes the header so each translation unit ends up with a 'copy' of the string with the same name, the result is that each translation unit compiled correctly. However when linking multiple translation units have the same symbol (the string) and that provoke the link error due to the symbolic link. – Javier Mr Feb 24 '17 at 08:28
12

You need to put the line

const std::string MainController::SOME_URL = "www.google.com";

in the cpp file, not the header, because of the one-definition rule. And the fact that you cannot directly initialize it in the class is because std::string is not an integral type (like int).

Alternatively, depending on your use case, you might consider not making a static member but using an anonymous namespace instead. See this post for pro/cons.

Community
  • 1
  • 1
JRL
  • 76,767
  • 18
  • 98
  • 146
  • Even if it's integral type, it will give error. That is, it has NOTHING to do with the *type* of the static member; as long as you provide *definition* of the member in the header, it will give error. – Nawaz Sep 27 '11 at 15:09
  • 1
    @Nawaz In practice. Formally, multiple definitions in difference translation units is undefined behavior, so a compiler could make it work. (Or do anything else, but "make it work" was a common implementation in C. Where constructors didn't enter into it.) – James Kanze Sep 27 '11 at 15:13
  • 1
    @JamesKanze: What are you trying to say? That it has to do with *type* of the static member? – Nawaz Sep 27 '11 at 15:15
  • @Nawaz: for the part about integral types, I am referring to providing a constant initializer within the class body in the header, as in: `class A { static const int OBVIOUS = 1;}`. – JRL Sep 27 '11 at 15:19
  • @JRL: But that is not what OP is doing. You're mixing two things together. – Nawaz Sep 27 '11 at 15:19
  • 1
    @Nawaz: I know that's not what the OP is doing. The OP mentions he is rusty in C++. I am merely adding some information as to how to initialize the string (put it in the cpp), that if it was an int it could be initialized directly in the class body, and that an anonymous namespace might be useful in some cases. – JRL Sep 27 '11 at 15:24
  • @JRL: You current answer doesn't say what you're saying in the comment. In your answer, you didn't even talk about *in-class* initialization (which is allowed for integral type only). – Nawaz Sep 27 '11 at 15:26
  • 1
    @Nawaz It has nothing to do with the type. Multiple definitions in separate translation units is undefined behavior, and a compiler is allowed to make it work. Traditionally, C compilers did (for historical reasons); C++ compilers haven't. Probably because with older linkers, it's very difficult to make it work when there is dynamic initialization. In practice, with a C++ compiler, you will get an error. – James Kanze Sep 27 '11 at 15:35
  • @JamesKanze: Ohh I see. At first I thought you are agreeing JRL, implying it has to do with the *type* of the member. After reading your comment, I should rephrase my very first comment as: **In practice, even if it's integral type, it will give error. That is, it has NOTHING to do with the *type* of the static member; as long as you provide *definition* of the member in the header, it will give error (in practice).** – Nawaz Sep 27 '11 at 15:42
  • @Nawaz: I clarified the post. Enjoy! ;-) – JRL Sep 27 '11 at 15:50
  • @JRL: Removed `-1`. and then upvoted. +1. Enjoy! ;-) :D – Nawaz Sep 27 '11 at 15:51
  • 2
    @Nawaz I wasn't trying to say that you were wrong; for all intents and purposed, today in C++, you're right. I was just throwing in some additional information: historical and standardese, but nothing to change the impact of what you had written. – James Kanze Sep 27 '11 at 16:00
  • @JamesKanze: I must thank you for the information which you provided in the comments. Honestly, I didn't know that. Thanks. :-) – Nawaz Sep 27 '11 at 16:03
4

Define the class in the header file:

//file.h
class MainController{
private:
    static const std::string SOME_URL;
}

And then, in source file:

//file.cpp
 #include "file.h"

const std::string MainController::SOME_URL = "www.google.com";
Nawaz
  • 353,942
  • 115
  • 666
  • 851
2

You should put the const std::string MainController::SOME_URL = "www.google.com"; definition into a single source file, not in the header.

Mark B
  • 95,107
  • 10
  • 109
  • 188