6

When I declared and initialized a const object.

// ConstClass.h
class ConstClass
{
};

const ConstClass g_Const;

And two cpp files include this header.

// Unit1.cpp
#include "ConstClass.h"
#include "stdio.h"

void PrintInUnit1( )
{
    printf( "g_Const in Unit1 is %d.\r\n", &g_Const );
}

and

// Unit2.cpp
#include "ConstClass.h"
#include "stdio.h"

void PrintInUnit2( )
{
    printf( "g_Const in Unit2 is %d.\r\n", &g_Const );
}

When i build the solution, there was no link error, what you will get If g_Const is a non-const fundamental type!

And PrintInUnit1() and PrintInUnit2() show that there are two independent "g_Const"s with different address in two compilation units, Why?

==============

I know how to fix it.(use extern keyword to declaration, and define it in one cpp file.)

I wonder to know why I did't get redfined link error in this sample.

all4register
  • 93
  • 1
  • 5

2 Answers2

9

https://stackoverflow.com/a/6173889/1508519

const variable at namespace scope has internal linkage. So they're basically two different variables. There is no redefinition.

3.5/3 [basic.link]:

A name having namespace scope (3.3.5) has internal linkage if it is the name of

— an object, reference, function or function template that is explicitly declared static or,

— an object or reference that is explicitly declared const and neither explicitly declared extern nor previously declared to have external linkage; or

— a data member of an anonymous union.

Use extern if you want it to have external linkage.


As stated in the other answer, header files are just pasted in cpp files. The same header file is included in both cpp files, but they are separate translation units. That means that one instance of a variable is different from the other instance. In other to let the compiler know that you have defined the variable elsewhere, use the extern keyword. This ensures only one instance is shared across translation units. However extern const Test test is just a declaration. You need a definition. It doesn't matter where you define it as long as it is defined once in some cpp file. You can declare it as many times as you want (which is convenient for placing it in a header file.)

So for example:

Constant.h

class Test
{
};

extern const Test test;

Unit1.cpp

#include "Constant.h"
#include <iostream>

void print_one()
{ std::cout << &test << std::endl; }

Unit2.cpp

#include "Constant.h"
#include <iostream>

void print_two()
{ std::cout << &test << std::endl; }

main.cpp

extern void print_one();
extern void print_two();

int main()
{
   print_one();
   print_two();
}

Constant.cpp

#include "Constant.h"
const Test test = Test();

Makefile

.PHONY: all
all:
   g++ -std=c++11 -o test Constant.cpp Unit1.cpp Unit2.cpp main.cpp
Community
  • 1
  • 1
  • 1
    Re "It doesn't matter where you define it as long as it is defined once in some cpp file.", this is (pedantically) incorrect. First, the language specification doesn't have any notion of source file, and no distinction between header and cpp. Secondly, for the in-practice there are two (with C++11 three) general methods of defining such a constant in a header, without any One Definition Rule problems. – Cheers and hth. - Alf Dec 21 '13 at 08:44
  • Does this solve "initialization fiasco"? Can I access variable from any (other) compilation unit (e.g. `Unit2.cpp`) and be sure that it has been initialized (within `Constant.cpp`)? If it doesn't solve initialization problem, then main may print nullptrs randomly.... – Martin Dvorak Jan 10 '17 at 08:07
5

Because you put variable definition in header file. Including header file is just like replacing it with the content of the file. So, the first file:

// Unit1.cpp
#include "ConstClass.h"  // this will be replace with the content of ConstClass.h
#include "stdio.h"

void PrintInUnit1( )
{
    printf( "g_Const in Unit1 is %d.\r\n", &g_Const );
}

will become (after preprocessing phase before compiling):

// Unit1.cpp
// ConstClass.h
class ConstClass
{
};

const ConstClass g_Const;
//this line is replaced with the content of "stdio.h"

void PrintInUnit1( )
{
    printf( "g_Const in Unit1 is %d.\r\n", &g_Const );
}

And the second file will be:

// Unit2.cpp
// ConstClass.h
class ConstClass
{
};

const ConstClass g_Const;
//this line is replaced with the content of "stdio.h"

void PrintInUnit2( )
{
    printf( "g_Const in Unit2 is %d.\r\n", &g_Const );
}

As you can see, each file has separate variable g_Const (this is just for the case of your code in here, there maybe no variable at all just like macro, see explanation in my last paragraph).

If what you want is not the definition of the variable just the declaration in the header file, you should use extern keyword in the header file:

extern const ConstClass g_Const;

Then you can put the definition of g_Const variable in ConstClass.c


There is some catch in your code:

  • there is no constant value assigned in your g_Const definition, you must assign it a constant value in the definition unless you want the default value (0).
  • inside printf, you take the address of const variable of C++. This actually force the compiler to create the variable in stack. If you don't take the address it may be able to infer a compile time number behaving like macro in C (you can get the magic number directly put in the code where you use the const variable).
dragon135
  • 1,366
  • 8
  • 19