brenzo
brenzo

Reputation: 769

Why doesn't #pragma once guard against multiple non-constexpr definitions?

Just spent a while debugging a multiple definition error but I'm unclear on why this behavior occurred and would like to understand.

I had something similar to this in a header file.

//foo.h
#pragma once

my_states States[N] = {...};

Later, bar.h includes foo.h as bar.cpp has functions which need to know about my_states.

The issue arose when I was writing unit tests for bar and included bar.h in test.cpp.

bar.o: multiple definition of MyNamespace::named_states
test.o: first defined here

I have fixed the issue by changing to

constexpr my_states States[n] = {...}; in foo.h.

However I do not understand why this fixed the issue. I understand I had multiple definitions for the symbol my_states which confused the linker, but if I have my #pragma once guard in place, why was this being defined multiple times? I'm unsure why I need the constexpr qualifier to denote that this should only have 1 definition, when as far as I understand #pragma once should have prevented the compiler from attempting to create more than 1 definition in the first place.

Upvotes: 0

Views: 934

Answers (1)

ALX23z
ALX23z

Reputation: 4713

#pragma once only ensures that header files are included once only, it doesn't deal with the code.

On your second question regarding my_states - without constexpr you attempt to define a global variable that can be modified in runtime (or something like that). By settings its state in the header, you defacto make each library that includes this header file instantiate and contain the variable while it is supposed to be uniquely defined... basically it's a complete mess that cannot compile. You can declare static/global variables in header files but you ought to instantiate them in a single cpp file.

By adding constexpr to the variable declaration you convey to compiler that it cannot be modified in runtime, and moreover, it's value is known at compile time. So there is no worry about which library stores / instantiates it or anything of the sort since it is an absolute constant known at compile time.

Upvotes: 1

Related Questions