Question --Why "undefined reference" linker error, when trying to use a static class member that is a pointer to another class?

Steve Petrie, P.Eng. apetrie@aspetrie.net
Wed Oct 19 10:42:00 GMT 2016


Greetings to gcc-help@gcc.gnu.org

I am trying to use a C++ class to encapsulate some (static) variables to 
be shared by multiple programs all linked into a single executable.

The idea is to avoid using extern variables.

I'm getting an "undefined reference" error from the linker step in g++.

The actual console application code exhibiting the "undefined reference" 
error is rather complex, so I have created a small console application 
example that illustrates the problem.

I attach the following files:

==> program that "encapsulates" the 3 static member variables:

   <sub1.h>;
   <sub1.cpp>;

==> program that tries to use the 3 static member variables:

   <testns_main.h>;
   <testns_main.cpp>;
   <main.cpp>;

But I also paste these small files into this message, for the 
convenience of readers.

* * *
* * *

Here is the program that has the"encapsulation" class definition:

// sub1.h ...

#ifndef SUB1_H_INCLUDED
#define SUB1_H_INCLUDED

// class pointed to by class sub1 member sub1_ptr_sub0.
class
sub0
{
public:

   sub0();
   ~sub0();

   int sub0_int;
};

// "encapsulation" class with static data_members.
class sub1
{
public:

   // Static member declarations.
   static int sub1_int;
   static int* sub1_ptr_int;
   static sub0* sub1_ptr_sub0;

   // non-static member declaration.
   int sub1_int2;
};

#endif // SUB1_H_INCLUDED

// ... sub1.h.

// sub1.cpp ...

#include "sub1.h"

// Define static members in file scope.
int sub1::sub1_int;
int* sub1::sub1_ptr_int = &sub1::sub1_int;
sub0 sub1::*sub1_ptr_sub0;

sub0::sub0(){};
sub0::~sub0(){};

// ... sub1.cpp.

* * *
* * *

Here is the program that tries to use the three static members in the 
"encapsulation" class sub1:

// testns_main.h ...

#ifndef TESTNS_MAIN_H_INCLUDED
#define TESTNS_MAIN_H_INCLUDED

namespace ns_main
{
   int
   testns_main_func();

} // ... namespace ns_Mainline.

// Define testns_main_func in file scope.
// using ns_main::testns_main_func;

#endif // TESTNS_MAIN_H_INCLUDED

// ... testns_main.h.

// testns_main.cpp ...

#include <iostream>

using namespace std;

// must include class definition at file scope.
#include "..\dbxdig_testns_sub1\sub1.h"

namespace ns_main
{
// Define a dummy (non-evaluated) object;
  sub1 sub1Object;

   int testns_main_func()
   {
       cout << "\n" << "testns_main_func() starting..." << endl;

       cout << "\n" << "sub1Object.sub1_int is accessible" << endl;

       cout << "\n" << "sub1Object.sub1_int<" << sub1Object.sub1_int << 
"> (value as initialized by constructor)" << endl;
       sub1Object.sub1_int = 1;
       cout << "\n" << "sub1Object.sub1_int<" << sub1Object.sub1_int << 
"> (value assigned by \"=\" in this function)" << endl;

       int i = 3;
       cout << "\n" << "i<" << i << "> (value as initialized by \"=\" in 
this program)" << endl;
       sub1Object.sub1_ptr_int = &i;
       *sub1Object.sub1_ptr_int = 4;
       cout << "\n" << "i<" << i << "> (value assigned through pointer 
sub1Object.sub1_ptr_int in this function)" << endl;

// line 31: the line that triggers the "undefined reference" linker 
error.
     sub1Object.sub1_ptr_sub0 = NULL;

       cout << "\n" << "(sub1Object.sub1_ptr_sub0 is accessible in this 
function)" << endl;

       cout << "\n" << "testns_main_func() finished..." << endl;

       return 0;
   }
}

// ... testns_main.cpp.

// main.cpp ...

#include <iostream>

using namespace std;

#include "testns_main.h"

int
main()
{
   int return_code;

   cout << "starting<testns_main_func()> ..." << "\n";

 return_code = ns_main::testns_main_func();

   cout << "\n" << "... finished<testns_main_func()> return_code<" << 
return_code << ">" << "\n";
   cout << "\n" << "press<CTRL-c> to exit" << "\n";

   string response;
 cin >> response;

 return return_code;

} // ... int main( void ).

// ... main.cpp.

* * *
* * *

The build of the "encapsulation" program (sub1.h, sub1.cpp) completes 
without errors or warnings. Here is the log from the build in the 
CodeBlocks IDE:

-------------- Clean: Debug in dbxdig_testns_sub1 (compiler: GNU GCC 
Compiler)---------------

Cleaned "dbxdig_testns_sub1 - Debug"

-------------- Build: Debug in dbxdig_testns_sub1 (compiler: GNU GCC 
Compiler)---------------

mingw32-g++.exe -Wall -g -Wall -g -DWIN32  -c "F:\U S R\A S 
P\DIGDIG\CodeBlocks 
Projects\dbxdig\dbxdig_test_ns\dbxdig_testns_sub1\sub1.cpp" -o 
obj\Debug\sub1.o
cmd /c if exist bin\Debug\libdbxdig_testns_sub1.a del 
bin\Debug\libdbxdig_testns_sub1.a
ar.exe -r -s bin\Debug\libdbxdig_testns_sub1.a obj\Debug\sub1.o
ar.exe: creating bin\Debug\libdbxdig_testns_sub1.a
Output file is bin\Debug\libdbxdig_testns_sub1.a with size 2.97 KB
Process terminated with status 0 (0 minute(s), 2 second(s))
0 error(s), 0 warning(s) (0 minute(s), 2 second(s))

* * *
* * *

However, the build of the program (main.cpp, testns_main.cpp) that tries 
to use the three static members in the "encapsulation" class, fails with 
a linker error:

   "undefined reference to `sub1::sub1_ptr_sub0'".

Here is the log from the build in the CodeBlocks IDE:

-------------- Clean: Debug in dbxdig_testns_main (compiler: GNU GCC 
Compiler)---------------

Cleaned "dbxdig_testns_main - Debug"

-------------- Build: Debug in dbxdig_testns_main (compiler: GNU GCC 
Compiler)---------------

mingw32-g++.exe -Wall -fexceptions -std=c++98 -g -Wall -g -DWIN32  -c 
"F:\U S R\A S P\DIGDIG\CodeBlocks 
Projects\dbxdig\dbxdig_test_ns\dbxdig_testns_main\main.cpp" -o 
obj\Debug\main.o
mingw32-g++.exe -Wall -fexceptions -std=c++98 -g -Wall -g -DWIN32  -c 
"F:\U S R\A S P\DIGDIG\CodeBlocks 
Projects\dbxdig\dbxdig_test_ns\dbxdig_testns_main\testns_main.cpp" -o 
obj\Debug\testns_main.o
mingw32-g++.exe -L"I:\U S R\A S P\Projects - MS VS 
8\gd-2.0.33-msvc8\gdwin32" -o bin\Debug\dbxdig_testns_main.exe 
obj\Debug\main.o obj\Debug\testns_main.o 
..\dbxdig_testns_sub1\bin\Debug\libdbxdig_testns_sub1.a
obj\Debug\testns_main.o: In function `ZN7ns_main16testns_main_funcEv':
F:/U S R/A S P/DIGDIG/CodeBlocks 
Projects/dbxdig/dbxdig_test_ns/dbxdig_testns_main/testns_main.cpp:32: 
undefined reference to `sub1::sub1_ptr_sub0'
collect2.exe: error: ld returned 1 exit status
Process terminated with status 1 (0 minute(s), 8 second(s))
1 error(s), 0 warning(s) (0 minute(s), 8 second(s))

* * *
* * *

If I comment out the "offending" line 32 in program testns_main.cpp (and 
also comment out the associated cout line), the build completes without 
errors, and the progrram runs to completion.

Here is the output from the program in the command line console window:

starting<testns_main_func()> ...

testns_main_func() starting...

sub1Object.sub1_int is accessible

sub1Object.sub1_int<0> (value as initialized by constructor)

sub1Object.sub1_int<1> (value assigned by "=" in this function)

i<3> (value as initialized by "=" in this program)

i<4> (value assigned through pointer sub1Object.sub1_ptr_int in this 
function)

testns_main_func() finished...

... finished<testns_main_func()> return_code<0>

press<CTRL-c> to exit

Use of the two other static data members works OK. It's only the use of 
the static data member that points to objects of another class, that 
gives the "undefined reference" error in the linker.

* * *
* * *

So, my question is:

Why does the program (main.cpp, testns_main.cpp) build and run OK, when 
line 32 is commented out, so there is no use of the variable (repeated 
here from line 32):

   sub1Object.sub1_ptr_sub0 = NULL;

that points to objects of class sub0?

But when line 32 is not commented out, the build of the program fails in 
the linker step, with an "undefined reference" error:

obj\Debug\testns_main.o: In function `ZN7ns_main16testns_main_funcEv':
F:/U S R/A S P/DIGDIG/CodeBlocks 
Projects/dbxdig/dbxdig_test_ns/dbxdig_testns_main/testns_main.cpp:32: 
undefined reference to `sub1::sub1_ptr_sub0'

Why ???

Comments, questions greatly appreciated!!

Steve

* * *

Steve Petrie, P.Eng.

Oakville, Ontario, Canada
(905) 847-3253
apetrie@aspetrie.net 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: main.cpp
Type: text/x-c++src
Size: 479 bytes
Desc: not available
URL: <https://gcc.gnu.org/pipermail/gcc-help/attachments/20161019/9d356997/attachment.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: testns_main.cpp
Type: text/x-c++src
Size: 1322 bytes
Desc: not available
URL: <https://gcc.gnu.org/pipermail/gcc-help/attachments/20161019/9d356997/attachment-0001.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: testns_main.h
Type: text/x-chdr
Size: 303 bytes
Desc: not available
URL: <https://gcc.gnu.org/pipermail/gcc-help/attachments/20161019/9d356997/attachment-0002.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: sub1.cpp
Type: text/x-c++src
Size: 218 bytes
Desc: not available
URL: <https://gcc.gnu.org/pipermail/gcc-help/attachments/20161019/9d356997/attachment-0003.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: sub1.h
Type: text/x-chdr
Size: 479 bytes
Desc: not available
URL: <https://gcc.gnu.org/pipermail/gcc-help/attachments/20161019/9d356997/attachment-0004.bin>


More information about the Gcc-help mailing list