3

There are too many different answers on stack overflow:

  1. Declare a namespace, and in the hpp file mark all strings as extern const, and in the cpp file put their definitions.

    C++ How to share constants with extern between cpp - Error: storage class specified

  2. Use static const instead of extern const:

    https://softwareengineering.stackexchange.com/questions/351827/is-it-bad-practice-to-define-constants-using-class-static-methods

  3. Use an inline function :

    static string constants in class vs namespace for constants [c++]

  4. Use anonymous namespaces!

    Where do I put constant strings in C++: static class members or anonymous namespaces?

This is all really confusing. Using an inline function seems like a really lengthy and tedious way to return a string constant.

Why can't we just use namespaces containing static strings, which are defined in the cpp file ?

Can someone please provide an categorical / unequivocal answer of how one should store strings in a constant file, so multiple cpp files can access them ?

EDIT: In C# and Java it seems to be a non-issue to store all your constants in a "Constants" file. What is the easiest way to do this in C++ ?

EDIT: These answers in Java seem specific and understandable. In C++ it is unclear which is the way likely to have least compilation time, least memory usage at run time.

Sharing constant strings in Java across many classes?

https://dzone.com/articles/constants-in-java-the-anti-pattern-1

James Z
  • 12,209
  • 10
  • 24
  • 44
Rahul Iyer
  • 19,924
  • 21
  • 96
  • 190
  • Just to clarify: You want to have a `.hpp` file, which will be included in multiple translation units, allow them all to use some string constants, but have them stored just once in the linked binary. Am I right? – einpoklum Apr 03 '19 at 09:56
  • 3
    Unfortunately there's no "categorical / unequivocal" way, there is no single "correct" or "right" way to do this. That makes this question subjective. – Some programmer dude Apr 03 '19 at 10:00
  • @Someprogrammerdude Which way would have the least compilation time, and use the least amount of memory and processor time, with least risk of errors then ? – Rahul Iyer Apr 03 '19 at 10:02
  • 1
    What exactly is the goal of "accessing string constants from multiple classes"? Why do multiple classes depend on the same constants in the first place? How exactly are you planning to "access" the string constants? Via a name? Via an index? Is this to implement internationalization? What type of string are we talking about? `const char[N]`? `std::string`? something else? This question is way to vague and general as that a useful answer could be given… – Michael Kenzel Apr 03 '19 at 10:02
  • @MichaelKenzel It is not for internationalisation. It is for storing event names. Any class can register for specific events, and it isn't known ahead of time which class would like to register for which event. Thats why multiple classes need to access the file. – Rahul Iyer Apr 03 '19 at 10:03
  • 1
    Why do event names have to be strings? Couldn't you just use, e.g., an enum for that!? – Michael Kenzel Apr 03 '19 at 10:04
  • 1
    @KaizerSozay In this case, using a header file with static const char* will help. – cpp_enthusiast Apr 03 '19 at 10:04
  • @MichaelKenzel This is the requirement, and unfortunately I am not in a position to argue about why it should be a string. – Rahul Iyer Apr 03 '19 at 10:05
  • 2
    That's fair enough. I suggest that you edit your question to make it a concrete question about your concrete problem so that a concrete answer can be given. – Michael Kenzel Apr 03 '19 at 10:06
  • @MichaelKenzel I am looking for an answer similar to that in this question: https://stackoverflow.com/questions/10896111/sharing-constant-strings-in-java-across-many-classes – Rahul Iyer Apr 03 '19 at 10:11
  • 1
    "The least compilation time, and use the least amount of memory and processor time, with least risk of errors" You can never get all four, if you're lucky you can pick two. – Some programmer dude Apr 03 '19 at 10:11
  • @Someprogrammerdude Is there an answer you would suggest then ? – Rahul Iyer Apr 03 '19 at 10:12
  • @KaizerSozay You can perform the benchmark on these 4 different implementations and can find out? Apart from that as per my knowledge, using "static const char* const" string literals should be fast during run time as everything will be in read-only section of the binary. – cpp_enthusiast Apr 03 '19 at 10:16
  • 3
    @KaizerSozay I think what others tried to say is that there is no _right answer_. This is quite usual with C++ that different approaches have different pros (and cons as well) and you cannot have all of them. Your question is too broad to provide generic advice. If you edit it to focus on your particular problem, you will likely get better answers. – Daniel Langr Apr 03 '19 at 10:32
  • @KaizerSozay By being more specific I meant to describe your real problem you were solving (you provided some more details in comments, but editing the question would be better). At best, you should provide a working example, such as some (minimal) code of, e.g., 2 source files that needs to share those string constants with a way of their usage. – Daniel Langr Apr 04 '19 at 12:18

4 Answers4

4

This question is way too broad to be answered. But based on further clarifications concerning the nature of the application (names used internally for registering events) given in comments, I would probably suggest something along the lines of using a header like this

#ifndef INCLUDED_EVENT_NAMES
#define INCLUDED_EVENT_NAMES

#pragma once

#include <string_view>

namespace event_names
{
    using namespace std::literals;

    inline constexpr auto name1 = "value1"sv;
    inline constexpr auto name2 = "value2"sv;
}

#endif

Using std::string_view constants rather than plain const char* or const char[N] means that you know the length of each string and don't have to rely on null termination. Using std::string would almost certainly entail memory overhead and initialization cost at runtime. The std::string_views defined here will compile down to code that's directly referring to statically-allocated string literal objects. Even when the same constant is used in multiple translation units (.cpp files) modern compilers will almost certainly store the same string literal in the binary only once (a standard optimization enabled by [lex.string]/15)

If you're stuck with C++11, then it's simplest (and most likely sufficient for what you need to do) to just make some named references for the string literal objects you need:

#ifndef INCLUDED_EVENT_NAMES
#define INCLUDED_EVENT_NAMES

#pragma once

namespace event_names
{
    constexpr auto& name1 = "value1";
    constexpr auto& name2 = "value2";
}

#endif

Since references are not objects, it is impossible for anyone to do anything (accidentally or otherwise) that would cause an actual object to be created for the constant itself (except for the string literal object of course). Also, since it's a reference, it will carry the information about the size of the array, in case anything may be able to take advantage of that (be aware that that size includes the terminating null). And since there still is the implicit conversion to const char* you will be able to use these whereever a plain old C-string is required.

Michael Kenzel
  • 15,508
  • 2
  • 30
  • 39
  • 1
    `std::string_view` is there from C++17. The question is tagged with C++11. (I would suggest to consider inline variables otherwise.) – Daniel Langr Apr 03 '19 at 10:53
  • Why haven't you used extern ? Wouldn't this result in multiple copies of constants, which isn't really useful ? – Rahul Iyer Apr 03 '19 at 11:02
  • 1
    @KaizerSozay Did you read the answer? It explains that linkers tend to be smart enough to merge the copies into just one for the final binary. And having the definitions be visible in each cpp _can_ allow for optimizations (thus increasing runtime speed, but possibly slowing compilation). It's all a tradeoff. But honestly, how many strings (and their uses) does your app involve that it's worth spending hours to find the most efficient storage concept for them? This all seems like premature optimization to me. – Max Langhof Apr 03 '19 at 11:03
  • @MaxLanghof Almost certainly is not the same as certainly – Rahul Iyer Apr 03 '19 at 11:06
  • 1
    @KaizerSozay And yet I'm _almost certain_ that none of this matters. Add your usage pattern to the question and we can tell you what would _probably_ be best for your particular case, which you can then confirm. If you don't do that then you won't get more than _almost certain_. For starters, we know neither your compiler nor your platform nor the number of strings (and how often they are used). Those are all important if you want any more precise answers. – Max Langhof Apr 03 '19 at 11:09
  • 1
    @KaizerSozay Also, you either have to trust your compiler (you have to do that at least in part anyway) or you have to check what it does (which you claim you don't want to do because you don't feel competent enough). If you trust your compiler, then stackoverflow answers won't be able to say more than "_probably_", because compilers change. And we can't check _your exact_ compiler if you don't tell us which one you're using (not that this is an absolute promise anyone would do so). – Max Langhof Apr 03 '19 at 11:13
  • @DanielLangr I indeed overlooked the C++11 tag, thanks for pointing that out. – Michael Kenzel Apr 03 '19 at 11:24
  • @KaizerSozay just to confirm, are you indeed restricted to C++11? – Michael Kenzel Apr 03 '19 at 11:24
  • @MichaelKenzel Yes. We are stuck with C++11 – Rahul Iyer Apr 03 '19 at 11:25
  • @KaizerSozay I updated my answer to account for that. – Michael Kenzel Apr 03 '19 at 12:06
  • @MichaelKenzel Since you mentioned it might be easier to give a concrete answer to a concrete question I created this: https://stackoverflow.com/questions/55498738/how-to-share-global-constants-with-minimum-overhead-at-runtime – Rahul Iyer Apr 03 '19 at 15:26
1

You need to define them in a C++ file (otherwise you will get multiple definitions error):

strings_id.cpp

const char* TXT_TEST1 = "Test1";

And you need to declare them in a header file that will be included where you need them:

strings_id.h

extern const char* TXT_TEST1;

Namespace usage recommended.

class1.cpp

#include "strings_id.h"
printf(TXT_TEST1);

class2.cpp

#include "strings_id.h"
printf(TXT_TEST1);
Max Langhof
  • 23,383
  • 5
  • 39
  • 72
cprogrammer
  • 5,503
  • 3
  • 36
  • 56
  • It seems that no one really knows the answer, since some people are using char* but other people say to only use std::string. Some use a static string, other people use extern. Why aren't you using a namespace in your answer then ? – Rahul Iyer Apr 03 '19 at 10:01
  • 2
    Haven't you gotten the first two files mixed up? You're declaring in the .cpp and defining in the .h . Also, suggest you use `.hpp` to distinguish from C headers. – einpoklum Apr 03 '19 at 10:09
  • 1
    @KaizerSozay No namespace is used because the answer doesn't change from doing it, and only you know what namespace grouping is best for your case. That's the same as an answer saying "pick better names" (because the context matters) and you asking "why didn't you pick better names" - it's not the point of the answer and doesn't do anything to clarify it. There are no include guards here either, even though you certainly _should_ have them. – Max Langhof Apr 03 '19 at 10:58
  • @KaizerSozay 1) Namespaces doesn't change the issue. 2) `std::string` is not recomanded for the example I have provided , It only create an instance more. Can be used, but you simply don't need a std::string here. 3) Who is saing to use static is wrong. static means the var will be available in the same stranlation unit. If you use `static`, you cannot use the varilable from h in other cpp file – cprogrammer Apr 03 '19 at 11:39
  • so why do you prefer extern to constexpr ? – Rahul Iyer Apr 03 '19 at 11:44
  • @KaizerSozay You mean `constexpr` to `const` ? – cprogrammer Apr 03 '19 at 11:45
  • AImx1's answer is similar to yours, but instead of using extern const, he is using constexpr const. – Rahul Iyer Apr 03 '19 at 11:48
  • `extern` tells the compiler the variable is declared in other module. `const` and newer `constexpr` is telling the variable cannot be changed. This because literal strings are stored in data section and any atempt to modify them will result in access violation. – cprogrammer Apr 03 '19 at 11:49
  • constexpr is const in c++11. If you don't have a portability issue you can use `constexpr`. There is no difference in the program generated. Edit2: `constexpr const` is not alowing you to assign ther value to that var. It's ok to use-it – cprogrammer Apr 03 '19 at 11:51
1

You cannot just define them in .cpp file because you want their declaration to be visible in other header and cpp files. You don't include .cpp files, so compiler won't know how to resolve your strings' names at compilation time. It will compile your definitions separately to an object file that corresponds to cpp file where you define the strings, but it won't be able to compile files that use the strings, and therefore link the program alltogether. You should use some way of declaring your strings (or way to access these strings, inline wrapper function for example) in a header file.

You can not just define them without any additional keyword in header file because it will create them in every object file that will be compiled from .cpp that includes this header.

So you should use some storage class keyword that will define the strings globally. You can read difference between static and extern in this question.

Anonymous namespace will make your string visible only in translation unit (.h or .cpp file) where you define them. So this is not what you want.

Also note that an inline function is implicitly extern.

Edit:

I personaly would use just extern keyword as I don't see any point in using inline wrapper functions. But you still could use them in combination with static for constants definition where you define your wrapper function. Still using only static keyword in constats definition will make constants accessible only from file where you define them.

Oliort UA
  • 1,568
  • 1
  • 14
  • 31
  • Thanks for your answer, but since there are so many ways of doing things it is still unclear to me how to solve the problem. – Rahul Iyer Apr 03 '19 at 10:15
  • 2
    @KaizerSozay Why not pick one solution, instead of worrying that there are multiple solutions. – john Apr 03 '19 at 10:18
  • @john To be honest John, there are so many different answers on SO of why to do / why not to do, it is really unclear. For most other things I am confident that my app won't have any problems after release, but since this is incredibly unclear, rather than "pick one" and risk my app having a terrible release, I would rather spend some time understanding which option is better, and why. – Rahul Iyer Apr 03 '19 at 10:21
  • @KaizerSozay added the way I would personally prefer in the edit. – Oliort UA Apr 03 '19 at 10:48
  • Can you post a code sample please ? – Rahul Iyer Apr 03 '19 at 10:49
  • @KaizerSozay cprogrammer posted code example in his answer, also you can find some in links you provided. – Oliort UA Apr 03 '19 at 10:58
  • @KaizerSozay Some of the issues you are worrying about are issues of style, so there is no clear best solution. For instance `std::string` vs `char*` and whether to use a namespace. – john Apr 03 '19 at 11:39
  • @john Ok. Thanks! But what I'm worrying about is if there are multiple copies of constants at runtime. – Rahul Iyer Apr 03 '19 at 11:43
0

Sharing constant strings in Java across many classes?

If you want some thing similar to that, then you can create a header file

#ifndef EVENT_NAME_LITERALS_HXX_
#define EVENT_NAME_LITERALS_HXX_

namespace eventnames
{
    constexpr const char* EVENT1 = "event1";
    constexpr const char* EVENT2 = "event2";
}

#endif

Let's name it as test.hpp

You can define the constants that you want in this header file and reuse the same in any CPP file you wish to use.

The below question provides more information:

use of constexpr in header file

constexpr implies const and const on global/namespace scope implies static (internal linkage), which means that every translation unit including this header gets its own copy of EVENT1 and EVENT2. The memory for that static is only going to be allocated if an address or reference to it is taken, and the address is going to be different in each translation unit.

That implied static for const variables was introduced specifically to use const instead of #define in header files in C++ to define constants. Without static there would be multiple symbol definitions linker error if that header file is included in more than one translation unit which were linked together.

If you don't want to have copies of the constants in each translation units that uses this header file, however the linker will be smart enough to optimize the multiple copies. Also you can "extern" as specified in other answers.

cpp_enthusiast
  • 1,239
  • 10
  • 28
  • 2
    `#define _TEST_HXX_` That identifier is reserved. By defining it, your program will have undefined behaviour. You should choose another header guard. – eerorika Apr 03 '19 at 10:14
  • Why didn't you use a namespace, and instead of char* why didn't you use std::string? Also why didn't you use extern in the header file, and specify the value of the strings in the cpp file ? – Rahul Iyer Apr 03 '19 at 10:14
  • @KaizerSozay There is no point in using anonymous namespaces in header file. I didn't use std::string because they are costly and in this case your event names don't change, so why can't they be string literals. – cpp_enthusiast Apr 03 '19 at 10:18
  • @eerorika Thanks for the hint, I updated my post – cpp_enthusiast Apr 03 '19 at 10:18
  • @AImx1 I didn't mean anonymous namespace . I mean why didn't you use a namespace like "EventNames" or something, so that we can group related constants together? – Rahul Iyer Apr 03 '19 at 10:19
  • 2
    @AImx1 `_CONST_STRING_LITERALS_HXX_` identifier is also reserved. – eerorika Apr 03 '19 at 10:20
  • @KaizerSozay sure, you can use anything you want. I just want to give you an idea of how to use. Anyhow I will update the post. – cpp_enthusiast Apr 03 '19 at 10:20
  • @AImx1If it is this simple, then can you explain why there are so many differing answers on SO ? It seems that this question should have been asked just once, and there should be one clear answer. – Rahul Iyer Apr 03 '19 at 10:23
  • 2
    @AImx1 `_EVENT_NAME_LITERALS_HXX_` is also a reserved indentifier. – eerorika Apr 03 '19 at 10:24
  • @KaizerSozay It all depends on the context in which you are trying to solve the issue. The solution which is ideal in one context might not be ideal in another context. So choose your context and then think about the solution. – cpp_enthusiast Apr 03 '19 at 10:25
  • @eerorika please suggest some identifier, I am out of ideas. – cpp_enthusiast Apr 03 '19 at 10:26
  • According to this question: https://stackoverflow.com/questions/3684450/what-is-the-difference-between-static-and-extern-in-c maybe static is the wrong option ? Because it seems like static should only be used locally within a file, but extern should be used for global variables – Rahul Iyer Apr 03 '19 at 10:26
  • 3
    @AImx1 for exaple `EVENT_NAME_LITERALS_HXX_`. I recommend looking up the language rules about reserved identifiers. – eerorika Apr 03 '19 at 10:27
  • This answer: https://stackoverflow.com/questions/34578993/c-how-to-share-constants-with-extern-between-cpp-error-storage-class-specif seems to make the most sense. But I don't understand what he means about using static objects ? – Rahul Iyer Apr 03 '19 at 10:30
  • why haven't you used extern then ? Won't you not want to have copies of constants in different translation units ? – Rahul Iyer Apr 03 '19 at 11:00
  • 1
    `constexpr` implies `const` by the way, so the last `const` in each declaration is pointless. – Max Langhof Apr 03 '19 at 11:29