8

So I know that in C++ constants get, by default, different linkage than variables. That's why I must not put

int foo;

in some header – the linker will rightly complain about multiple definitions. OTOH, I can write

const int bar = 42;

in a header, and the compiler makes sure there's only one definition of bar.

With integral constants, it is easy to see how the compiler deals with this – at least as long as nobody takes the address of bar or does some other funny thing requiring it to assign storage for it). However, what if someone does? And what if it isn't an integral but something that needs code to be executed at runtime? Assume I put this into a header:

const std::string baz = "h2g2";

Assuming no small string optimizations, this needs to allocate dynamic memory at runtime, so code needs to be executed, the address needs to be stored somewhere, etc.

I assume I would then end up with one definitions of baz per translation unit, only that the compiler assigns internal linkage to it to prevent the linker from complaining? Or am I missing something?

Note: I am not interested in constexpr, just in plain old C++ constants, as they existed since the 80s and were codified in C++98. (However, if a comprehensive answer would include how this all fits together with constexpr, I wouldn't complain about that.)

Community
  • 1
  • 1
sbi
  • 204,536
  • 44
  • 236
  • 426
  • You mean constants of non-primitive type. Floating point constants work the same way as integer constants. – Jason S Jul 16 '14 at 13:35
  • @TemplateRex: I've added note explaining this. – sbi Jul 16 '14 at 13:41
  • @JasonS: Well, not exactly - they can't be Integral Constant Expressions for instance. – MSalters Jul 16 '14 at 13:42
  • "the compiler makes sure there's only one definition of `bar`" - no it doesn't. It gives it internal linkage (as if you'd declared it `static`), so that it can be multiply defined. – Mike Seymour Jul 16 '14 at 13:45
  • @Mike TTBOMK, compilers can eliminate integral constants and use them as if they were literals. – sbi Jul 16 '14 at 13:46
  • @sbi: Indeed, if they're not odr-used. But that's got nothing to do with what I said; they're still defined in each translation unit that includes the definition, whether or not they're actually assigned storage. – Mike Seymour Jul 16 '14 at 13:52
  • @Mike. _In practice,_ most integral constants will very likely just evaporate. And I was asking about what happens if they can _not_ for whatever reasons, or if they cannot because they aren't integrals. – sbi Jul 16 '14 at 13:56
  • @sbi: As I said, and as the answer explains, it has internal linkage (as if you'd declared it static), so that it can be multiply defined. I was just trying to correct your misapprehension that there would be only one definition, but it looks like I inadvertently created more confusion instead. Sorry. – Mike Seymour Jul 16 '14 at 14:00
  • @MikeSeymour: what's "odr-used"? – Jason S Jul 16 '14 at 18:13
  • 1
    @JasonS: Basically, used in such a way that it needs a definition (e.g. taking its address). The full definition is rather complicated; see section 3.2 of the C++ standard, if you want the gory details. "odr" stands for "one definition rule", which is the rule determining when and how things need to be defined. – Mike Seymour Jul 17 '14 at 12:43

1 Answers1

4

Declaring an object (at namespace scope) as const in C++ assigns it internal linkage by default.

If you declare (and define because of the initialization)

const std::string baz = "h2g2";

into a header you will have a statically linked string per each translation unit. The address would have to be stored in each translation unit (different addresses per different non-heap stored char literals - read only memory)

Edit: As a C++11 digression constexpr implies const since it means "suitable for constant expressions evaluation", thus it should have internal linkage as well. [Nb. I'm not mentioning C++14]

Marco A.
  • 41,192
  • 25
  • 117
  • 233
  • SSO (Small String Optimization) applies to the content of `baz`, not the string literal. Your last sentence appears to confuse the two; SSO cannot affect the `char[]` literals – MSalters Jul 16 '14 at 13:41
  • @sbi in this case no SSO should happen because the data is a char literal whose address is known at compile time – Marco A. Jul 16 '14 at 13:43
  • 1
    @Marco note the "`constexpr` implies `const`" part [is untrue in C++14](http://akrzemi1.wordpress.com/2013/06/20/constexpr-function-is-not-const/) and thus should nog be relied on. – rubenvb Jul 16 '14 at 13:55
  • Thanks ruben, I'll add this to the answer in case someone doesn't see your comment – Marco A. Jul 16 '14 at 13:59
  • 2
    However, note that "`constexpr` implies `const`" is indeed true for variables, even in C++14. – R. Martinho Fernandes Jul 16 '14 at 14:00