1

For some reasons, sometimes when I define my member functions in a CPP file rather than within their declaring header, I get undefined reference errors from g++. This question is similar to Undefined Reference To Member function but that user managed to solve the problem by adding the missing file to his command line, which doesn't seem to be working here. Btw, I'm not against using a makefile; in fact I plan to do so eventually, whenever I get used to these commands.

my main file ('ringbuftest.cpp'):

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <iostream>
#include <cstring>
#include "ringbuffer.h"
using namespace std;

void *reader(void* param);
void *writer(void* param);

struct pack{
  char msg[256];
};

RINGBUFFER<pack> *ringo;

int main(){
pthread_t rdr;
pthread_t wtr;

ringo = new RINGBUFFER<pack>(12);

int ret1 = pthread_create(&rdr,NULL,reader,(void*)NULL);
int ret2 = pthread_create(&wtr,NULL,writer,(void*)NULL);

#ifdef _unix
cout<< "unix single underscore\n";
#elif defined __unix
cout<< "unix two underscores\n";
#endif

pthread_join(wtr,NULL);
pthread_join(rdr,NULL);

cout<< "threads are done\n";
exit(0);
return 0;
}

void *reader(void *param){
  pack myPack;
  while(true)
  {
    for(int i=0;i<10000;i++){int k=0;k=i;k++;i=k;i--;}
    if( ringo->Pop(&myPack) )
    {
      cout<< myPack.msg;
    }
  }
}
void *writer(void *param){
  pack myPack;
  while(true){
    strcpy(myPack.msg,"hello reader!\n");
    ringo->Push(&myPack);
  }
}

my class header ('ringbuffer.h'):

#include<stdlib.h>
using namespace std;

#ifndef __ring_buffer_h__
#define __ring_buffer_h__

#define RINGBUFFER_DEFAULT_SIZE 8

template <class T>
class RINGBUFFER
{
private:
    unsigned int top;
    unsigned int bottom;
    unsigned int size;
    unsigned int count;
    void *items;
public:
    RINGBUFFER();
    RINGBUFFER(unsigned int size);
    ~RINGBUFFER();
    bool Push(T *value);
    bool Pop(T *value);
};


#endif

my class definitions ('ringbuffer.CPP'):

#include "ringbuffer.h"

template<class T>
RINGBUFFER<T>::RINGBUFFER()
{
    top = bottom = 0;
    size = RINGBUFFER_DEFAULT_SIZE;
    count = 0;
    items = malloc((size+1)*sizeof(T));
}

template<class T>
RINGBUFFER<T>::RINGBUFFER(unsigned int _size)
{
    top = bottom = 0;
    size = _size;
    count = 0;
    items = malloc(size*sizeof(T));
}

template<class T>
RINGBUFFER<T>::~RINGBUFFER()
{
    free(items);
}

template<class T>
bool RINGBUFFER<T>::Push(T *value)
{
    if( count<size )
    {
        memcpy(&(((T*)items)[bottom]),value,sizeof(T));
        bottom = (bottom+1)%size;
        count++;
        return true;
    }
    return false;
}

template<class T>
bool RINGBUFFER<T>::Pop(T *value)
{
    if( count>0 ) 
    {
        memcpy(value,&(((T*)items)[top]),sizeof(T));
        top = (top+1)%size;
        count--;
        return true;
    }
    return false;
}

To compile, I've been trying to use:

g++ ringbuffer.CPP ringbuftest.cpp -lpthread -o ringbuffertest.o

and I get the errors:

/tmp/ccj8RqhY.o: In function `main':
ringbuftest.cpp:(.text+0x21): undefined reference to `RINGBUFFER<pack>::RINGBUFFER(unsigned int)'
/tmp/ccj8RqhY.o: In function `reader(void*)':
ringbuftest.cpp:(.text+0x157): undefined reference to `RINGBUFFER<pack>::Pop(pack*)'
/tmp/ccj8RqhY.o: In function `writer(void*)':
ringbuftest.cpp:(.text+0x1db): undefined reference to `RINGBUFFER<pack>::Push(pack*)'
collect2: error: ld returned 1 exit status

I'm guessing I'm doing something wrong with g++ because I keep hitting this problem in different projects, or maybe I'm using templates wrong.(?) How can I resolve this error?

Edit: I should mention that this compiles perfectly if I instead paste the member definitions into the header file and exclude the .CPP from the g++ command.

3
  • possible duplicate of C++ undefined reference to template class method Commented Mar 2, 2013 at 15:23
  • 1
    Also don't use -lpthread. Use -pthread instead. (Unless you have a very good reason not to.) Commented Mar 2, 2013 at 15:24
  • Do not put double underscores in your include guards, all names with double underscores are reserved for the implementation. Do not put using namespace in a header. Your include guards should be at the top of the file, not after the #include and the very naughty using. Finally, naming a class template in ALL_CAPS is weird. Commented Mar 4, 2013 at 21:27

1 Answer 1

1

You need to move the entire definition of RINGBUFFER<T> from ringbuffer.cpp to ringbuffer.h so that it's visible when ringbuftest.cpp is being compiled.

Sign up to request clarification or add additional context in comments.

1 Comment

is this specific to template classes? I had this same error on a non-template class until I rearranged the order of files on the compile command, into order of dependency.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.