non-integral constants

前端 未结 5 1464
-上瘾入骨i
-上瘾入骨i 2020-12-28 08:39

I want a header file with a non-integral constant in it, e.g. a class. Note the constant does not need to be a compile-time constant.

stati         


        
相关标签:
5条回答
  • 2020-12-28 09:23

    You seem to have them mixed up.

    You are right about

    static const std::string Ten = "10"; 
    

    version. It will "work", but it will create a separate object in each translation unit.

    The version without static will have the same effect. It won't produce linker errors, but will define a separate object in each translation unit. In C++ language const objects have internal linkage by default, meaning that

    const std::string Ten = "10"; // `static` is optional
    

    is exactly equivalent to the previous version with static.

    The version with extern and initializer

    extern const std::string Ten = "10"; // it's a definition!
    

    will produce a definition of an object with external linkage (it is a definition because of the presence of an initializer). This version will result in linker errors, since you'll end up with multiple definitions of an object with external linkage - a violation of ODR.

    Here's how you can do it:

    In order to achieve what you are trying to achieve, you have to declare your constant in the header file

    extern const std::string Ten; // non-defining declaration
    

    and then define it (with initializer) in one and only one of the implementation files

    extern const std::string Ten = "10"; // definition, `extern` optional
    

    (If the constant is pre-declared as extern, then extern in the definition is optional. Even without an explicit extern it will define a const object with external linkage.)

    0 讨论(0)
  • 2020-12-28 09:25

    It is a bad idea to create a static user-defined type in this way. You can't control the order of instantiation when you have multiple such UDTs. This is not a problem in a small project, but not all projects are small. It's a better idea to make your statics all plain old data types - raw pointers - and to initialize them in some appropriate way to point at the instances you need when the program starts up, or when you need them. This puts you in control.

    Your question stated that these types do not need to be compile-time constants. If so, and you have a multi-threaded program, your objects need to have their state protected from simultaneous access from multiple threads. If some of your objects are not thread-safe, then in addition to the object itself you need a mutex object to protect its state, and that has to have the same linkage, and will need initialization. All this complicates the global state of your program in what could be an unacceptable way.

    0 讨论(0)
  • 2020-12-28 09:25

    I think the other answers here are better, but if you're dead-set on doing it all with headers, you can effectively inline your object (as you specifically ask) with a simple wrapper function.

    inline const std::string &get_ten() {
        static const std::string ten = "10";
        return ten;
    }
    

    There will be only one string, initialized once, and you don't need anything outside of the header file.

    0 讨论(0)
  • 2020-12-28 09:36

    I don't know if there's a better way in C++ but the best way in C (which will also work in C++) is one of the ones you've listed.

    Have a separate compilation unit (eg,ten.cpp) holding just the data:

    const std::string Ten = "10";
    

    and a header file (eg,ten.h) declaring it so it can be used elsewhere:

    extern const std::string Ten;
    

    Then you just have to ensure any compilation unit that wants to use it include the header file (eg,ten.h), and any executable that wants to use it link with the separate compilation unit (eg,ten.o).

    This gives you one copy of the variable, accessible anywhere. Of course, you could just define it in the header file as static and have one copy per compilation unit. That would simplify what files you need to have and the static would ensure there's no doubly-defined symbols. But that's not something I'd ever recommend.

    I don't know why you state:

    but I'm afraid I'll get a linker error if I breath on it wrong

    This is accepted practice from long ago and you should know how all these things fit together if you wish to call yourself a C++ programmer (no insult intended).

    0 讨论(0)
  • 2020-12-28 09:40

    The extern version is close to what you want. Here:

    // in the file tenconstant.cpp
    const std::string Ten = "10";
    
    // in the file tenconstant.h
    extern const std::string Ten;
    
    // in your file
    #include "tenconstant.h"
    
    // do stuff with Ten
    

    You need it to be defined once for the linker, which is the purpose of myconstants.cpp, but declared everywhere you use it, which is the purpose of myconstants.h. This may seem a bit unwieldy for one variable, but for a larger project, you will probably have a nice header that gets used a lot that you can stick this in.

    0 讨论(0)
提交回复
热议问题