views:

423

answers:

8

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:

(Code formatting is buggy after enumerations.)

//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  
  1. Define them in an anonymous namespace in the cpp file:

(Code formatting is buggy after enumerations.)

//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.

+2  A: 

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
+4  A: 

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
+2  A: 

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
A: 

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
+14  A: 

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
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
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
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
A: 

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
A: 

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 .

anon
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
Is there any difference between these definitions and an anonymous namespace? It looks to me they are implicitly defined as "static".
stone
@Nemanja No, it won't. A const object declared at namespace scope is local to the translation unit.
anon
@Neil. You are right. In C++, constant values default to internal linkage.
Nemanja Trifunovic
@Neil: What is the difference between anonymous namespace and your answer, which doesn't use namespaces?
jasonline
@jasonline Less typing, less indentation, easier to read. The anonymous namespace does not add any information to the code, so it should be omitted.
anon
@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
@Johannes Could you expand on that a little in an answer? You know how much we love weird features!
anon
@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
@Johannes Well, as they say on the interweb - "Zoom!"
anon
A: 

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