28

I need to define some constant strings that will be used only by one class. It looks like I have three options:

  1. Embed the strings directly into locations where they are used.

  2. Define them as private static constant members of the class:

    //A.h  
    class A {  
    private:  
       static const std::string f1;  
       static const std::string f2;  
       static const std::string f3;  
    };  
    
    //A.cpp  
    const std::string f1 = "filename1";  
    const std::string f2 = "filename2";  
    const std::string f3 = "filename3";  
    
    //strings are used in this file  
    
  3. Define them in an anonymous namespace in the cpp file:

    //A.cpp  
    namespace {  
      const std::string f1 = "filename1";  
      const std::string f2 = "filename2";  
      const std::string f3 = "filename3";  
    }  
    
    //strings are used in this file  
    

Given these options, which one would you recommend and why? Thanks.

muru
  • 4,723
  • 1
  • 34
  • 78
stone
  • 293
  • 1
  • 3
  • 6
  • 7
    Notice that this is dangerous if you call the function that uses these strings from other translation units before main was started: The function might then access the string objects before they have been created. For that reason, i would get rid of the const std::string objects, and use `char const f1[] = "filename";` for this. – Johannes Schaub - litb Mar 18 '10 at 06:47
  • @litb: It seems you're saying it's safer to use primitive type char than the string object in this case? May I know the reason behind this? – jasonline Mar 18 '10 at 08:22
  • 4
    @jasonline, as i stated it in the comment: strings are complex objects, and initialized during startup of the program. If you have multiple such objects in different translation units, you don't know the order in which they are created, so if you refer to each other, you may refer to a not yet constructed string. Not so with the `char const[]` variant. – Johannes Schaub - litb Mar 18 '10 at 19:24

9 Answers9

21

I'd place them in anonymous namespace in the CPP file. It makes them private to the implementation and at the same moment makes it visible to the non-member functions that are part of implementation (such as operator<<).

Kirill V. Lyadvinsky
  • 97,037
  • 24
  • 136
  • 212
  • Thanks for the commment. I am also inclined toward this option. These strings would most like be constant. But if later on I decided to change one of the filenames, I can easily do it there without worrying to recomile everything that included the header file. – stone Mar 17 '10 at 20:51
  • Its worth noting that, even if you define them as static consts inside the class, the actual text will still have to be in the implementation file. So changing the filenames won't require recompiling anything except that one file. – Dennis Zickefoose Mar 17 '10 at 21:52
  • You're right, Dennis. It will only make a difference in terms of compling when adding/deleting these constants. Modifying them should be the same. – stone Mar 17 '10 at 23:56
  • With reference to the original question, the anonymous namespace is unnecessary as a const declared at file scope has internal linkage by default. If you are not concerned about name conflicts, then just get rid of the anonymous namespace. – dangerousdave Oct 18 '12 at 16:16
5

If they are used only in a single file then there is no need to expose them to the outside world by including them in the header file.

If they are used and will always be used only in a single place then there's really no reason not to just write them as literals where they need to be used.

If they are used in multiple places in the cpp, I would go for the anonymous namespace.

Another option which you don't mention is to define them as static variables inside the cpp. this is somewhat equivalent to the anonymous namespace option and more C-like than C++.

shoosh
  • 76,898
  • 55
  • 205
  • 325
3

Static members of the class.

If they are used in multiple places by the one class, it's usually easier to keep things organized - and to later find where you defined everything - if you keep them defined in the class that uses them. Defining them in-place makes them hard to locate and later modify. And I'd opt for the specific class over the anonymous namespace for cleaner class definition and use.

Rachel
  • 2,181
  • 2
  • 18
  • 20
2

If the strings are meant to be seen by users of the class, put them into the class. Otherwise, hide them in the implementation file's unnamed namespace.

sbi
  • 219,715
  • 46
  • 258
  • 445
2

If only used in the class's .cpp file, there is no need to use a namespace of any sort, simply say:

const std::string f1 = "filename1";  
const std::string f2 = "filename2";  
const std::string f3 = "filename3";  

Overuse of namespaces seems to be the new thing - I can't personally see the attraction .

  • 1
    But that may cause linker errors if there are names f1, f2, etc in other compilation units. That's why anonymous namespaces exist. – Nemanja Trifunovic Mar 17 '10 at 20:54
  • Is there any difference between these definitions and an anonymous namespace? It looks to me they are implicitly defined as "static". – stone Mar 17 '10 at 20:55
  • 2
    @Nemanja No, it won't. A const object declared at namespace scope is local to the translation unit. –  Mar 17 '10 at 21:05
  • @Neil. You are right. In C++, constant values default to internal linkage. – Nemanja Trifunovic Mar 17 '10 at 21:08
  • @Neil: What is the difference between anonymous namespace and your answer, which doesn't use namespaces? – jasonline Mar 18 '10 at 08:17
  • @jasonline Less typing, less indentation, easier to read. The anonymous namespace does not add any information to the code, so it should be omitted. –  Mar 18 '10 at 09:23
  • @jasonline, with anonymous namespaces, you can still pass the objects to templates as nontype arguments. But that's a weird feature you are likely never to use anyway... – Johannes Schaub - litb Mar 18 '10 at 19:25
  • @Johannes Could you expand on that a little in an answer? You know how much we love weird features! –  Mar 18 '10 at 19:31
  • @Neil ah but now i see they made it const *and* put it into an unnamed namespace! That's fun of course the unnamed namespace won't save us now if they are still const xD – Johannes Schaub - litb Mar 18 '10 at 20:02
  • @Johannes Well, as they say on the interweb - "Zoom!" –  Mar 18 '10 at 20:48
0

Just have the const strings at file scope in the implementation file, the anonymous namespace is not necessary to restrict their use to that class only.

C++ 003 Standard C.1.2 Clause 3: basic concepts

Change: A name of file scope that is explicitly declared const, and not explicitly declared extern, has internal linkage, while in C it would have external linkage

Note: The anonymous namespace does help reduce naming conflicts.

dangerousdave
  • 6,331
  • 8
  • 45
  • 62
0

Of the three options, the only one you should really avoid is #1. Don't use magic cookies in your code. By putting the constants either in a namespace or a class, you make it easier to extend and maintain your code in the future.

If your constants are global in nature, then between 2 and 3, it matters little. What matters is that you choose one and stick with it. But if you have constants that apply to a particular class, then they should be a part of that class.

Personally, I'd use a namespace for most things.

John Dibling
  • 99,718
  • 31
  • 186
  • 324
0

I think the real issue is: Are the strings really only used internally when implementing the class, or are they used elsewhere.

To be really nit-picky, I would try to keep the interface of the class as clean as possible, so if the filename-strings should not be of any interest to the "outside" world. I would hide them internally in the .cpp-file only. And in that case I don't think I would bother with the namespace, but just keep things "static" (i.e. internal to the .cpp-file).

S.C. Madsen
  • 5,100
  • 5
  • 32
  • 50
0

However you do it, one thing to be careful of: I wouldn't recommend using static std::string objects, instead use static char*. The reason for this is due to potential problems with order of initialisation. Say you have a static instance of a class whose constructor references the string A::f1. There is no guarantee that A::f1 has been constructed yet, and you'll get a crash, or worse, no crash but bogus data.

Tracking down order-of-initialisation bugs can be pretty nasty, and everything may look fine in one project, but then you might build another project using the same libraries, and the subtle differences in the link order will cause this bug to mysteriously appear.

the_mandrill
  • 29,792
  • 6
  • 64
  • 93