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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Greetings to gcc-help@xxxxxxxxxxx

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@xxxxxxxxxxxx
// 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.

// 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.
// 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.
// 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.
// 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.

[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux