Why getting linker error with vector? - c++

I have for homework to write my own abstract class Vector. I make some of the code, but when I try to compile it I have error. This is the code:
vector.hh:
#ifndef VECTOR__HH__
#define VECTOR__HH_
template<class T> class Vector {
int capacity_;
int size_;
T* buffer_;
void ensure_capacity(unsigned size);
public:
Vector(int capacity=10)
: capacity_(capacity), size_(0), buffer_(new T[capacity])
{ }
~Vector() {
delete []buffer_;
}
int size() const {
return size_;
}
bool empty() const {
return size_ == 0;
}
T& operator[](int n) {
return buffer_[n];
}
const T& operator[](int n) const {
return buffer_[n];
}
void clear() {
// TODO
}
int capacity() const {
return capacity_;
}
T& front() {
return buffer_[0];
}
const T& front() const {
return buffer_[0];
}
T& back() {
return buffer_[size_-1];
}
const T& back() const {
return buffer_[size_-1];
}
void push_back(const T& value);
};
#endif
vector.cc:
#include "vector.hh"
template<class T>
void Vector<T>::ensure_capacity(unsigned size) {
if(capacity_>size+1) {
return;
}
capacity_ = capacity_ ==0?1:capacity_;
while(capacity_<size+1) {
capacity_*=2;
}
T* old_buffer = buffer_;
buffer_ = new T[capacity_];
memcpy(buffer_, old_buffer, sizeof(T)*size_);
delete [] old_buffer;
}
template<class T>
void Vector<T>::push_back(const T& value) {
ensure_capacity(size()+1);
buffer_[size_] = value;
size_++;
buffer_[size_] = '/0';
}
main.cc:
#include "vector.hh"
#include <iostream>
using namespace std;
int main(int argc, char* argv[]) {
Vector<int> v(2);
v.push_back(10);
cout << v[0];
return 0;
}
And error is:
g++ -c -o main.o main.cc
g++ -Wall -g vector.o main.o -o hw02vector
main.o: In function 'main':
main.cc:(.text+0x37): undefined reference to 'Vector<int>::push_back(int const&)'
collect2: ld returned 1 exit status
make: * [hw02vector] Error 1

The linker error is coming because, for template classes the definition should always be visible. Either you can move all the content of vector.cc into vector.h. Or you can simply include vector.cc wherever you include vector.h.
side note:
Following lines in your .h file doesn't help:
#ifndef VECTOR__HH__
#define VECTOR__HH_
make both the macros similar such as, VECTOR__HH. This macros are used to avoid multiple inclusion of files.

In template programmming, the definition of the functions should be visible where the class template is defined. That is usually done by defining the functions inside the class itself.
So there are two ways you can solve your problem:
Move all the definitions from vector.cpp to vector.hh (which is in fact the usual solution). And delete Vector.cpp as its not needed.
Or, include the vector.cpp file at the end of vector.hh file, after the definition of Vector class template, like this:
#ifndef VECTOR__HH__
#define VECTOR__HH__ //<--- corrected this also!
template<class T>
class Vector {
//...
};
//...
#include "vector.cpp"
#endif VECTOR__HH__

Related

template array class is not working properly

Template class :
#ifndef ARRAYC_H
#define ARRAYC_H
#include <iostream>
using namespace std;
template <class T>
class Array
{
private:
T* m_ptr;
int m_size;
public:
Array();
Array(int size);
~Array();
int size() const;
bool is_Empty() const;
T& operator[](int index);
};
#endif
and class declaration Header..
#ifndef ARRAY_H
#define ARRAY_H
#include "ArrayC.h"
using namespace std;
template <class T>
Array<T>::Array(int size) {
if(size!=0) {
T* m_ptr = new T[size]{};
m_size = size;
}
}
template <class T>
Array<T>::~Array() {
cout <<"Deleted" << endl;
delete [] m_ptr;
}
template <class T>
int Array<T>::size() const {
return m_size;
}
template <class T>
bool Array<T>::is_Empty() const {
return (m_size==0);
}
template <class T>
T& Array<T>::operator[](int index) {
if(index< m_size) {
return m_ptr[index];
}
else {
cout <<"Index Specifed is out of Range" << endl;
exit(0);
}
}
#endif
program
#include "Array.h"
#include <iostream>
using namespace std;
int main() {
Array<int> A(2);
A[0] = 1;
A[1] = 2;
cout << A[0] << endl;
cout << A[1] << endl;
}
it compiles and also outputs value but
then it stops and then makefile shows error.
g++ -g -std=c++17 -c -o Main.o Main.cpp
g++ -g -std=c++17 -o Execute Main.o
Execute
1
2
Deleted
Makefile:13: recipe for target 'run' failed
mingw32-make: *** [run] Error -1073741819
after deleted is printed it stops for some time and then shows error.
run target only has one recipe that is to execute the program Execute.exe.
Really sorry for this type of description
but its doesnt show any type of error.
CCX_FLAGS = g++ -g -std=c++17
CCX_OF = -o
CCX_CF = -c
.PHONY : all preExwork Obclean Exclean
all : preExwork run Obclean
preExwork :
$(CCX_FLAGS) $(CCX_CF) $(CCX_OF) Main.o Main.cpp
$(CCX_FLAGS) $(CCX_OF) Execute Main.o
run :
Execute
Obclean :
del /f Main.o
Exclean :
del /f Execute.exe

How can I get rid of the <error-type> type that is appearing in my method template? Both the input to the method and the class are templates

I am getting the error
declaration is incompatible with "void spectrogram<T>::update(<error-type> x)
I don't see any difference between the declaration and the definition of the method, not sure why it is complaining about just this one definition and not the constructor or destructor.
Here is vComplex.hpp
#ifndef VCOMPLEX_H
#define VCOMPLEX_H
template <class T>
class vComplex {
public:
T* realp;
T* imagp;
int length; // for bookkeeping
vComplex(void) { }
vComplex (T* I, T* Q, int len) {
realp = I;
imagp = Q;
length = len;
}
~vComplex(void) {
free(realp);
free(imagp);
}
void put(T* I, T*Q, int len) {
realp = I;
imagp = Q;
length = len;
}
};
#endif
the function declaration for update in spectrogram.hpp, with other members removed:
#ifndef SPECTROGRAM_H
#define SPECTROGRAM_H
template <typename T>
class spectrogram {
public:
void update(vComplex<T> x);
};
#endif
and the function signature (and includes) for update in spectrogram.cpp:
#include <stdio.h>
#include <math.h>
#include "spectrogram.hpp"
#include "vComplex.hpp"
template <typename T>
void spectrogram<T>::update(vComplex<T> x) {
//do stuff
}
In VS 2017, I get the red underline under update and everything inside of it breaks basically. VS is saying T is undefined which I'm assuming is caused by the overall error. I have to use dynamically allocated pointers, I don't have the option of using other types or containers.

c++ undefined reference to function [duplicate]

This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 8 years ago.
I'm trying to implement a generic Queue class.
The Template class looks like it:
Queue.h
template <class T>
class Queue {
public:
Queue() {}
~Queue() {}
...
void enqueue( const T& e );
T dequeue( void );
int Size( void ) const { return s1.size() + s2.size();}
private:
std::stack<T> s1;
std::stack<T> s2;
};
#include "Queue.cpp"
And the implementation of it looks like it:
Queue.cpp:
#include "Queue.h"
template <class T>
void Queue<T>::enqueue( const T& e )
{
//...
}
template <class T>
T Queue<T>::dequeue ()
{
//...
}
my Problem is, i can't call some function of this class whtich I've implemented in the file Queue.cpp.
main.cpp:
int main() {
Queue<int> myQueue;
const int a = 1;
myQueue.enqueue(a);
myQueue.Size();
return 0;
}
i become always the follwing erro:
undefined reference to Queue::enqueue(int const&)
[Error] ld returned 1 exit status
Makefile.winrecipe for target 'MYQueue.exe' failed
Place the whole template definition including its member functions in one header file.

Linker error : unsolved external symbol [duplicate]

This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 9 years ago.
I'm trying to create a template c++ Stack, and i'm having some issue with the linker.
I've tried to put all the classes into one cpp file, and it works just fine, but the problem begin once I separate them into different files
here's my classes
main class :
#include <iostream>
#include "stack.h"
using namespace std;
int main()
{
Stack<double>* st = new Stack<double>();
st->push(new Data<double>(10));
cout << st->pop()->getData();
return 0;
}
stack.h :
#ifndef STACK_H
#define STACK_H
#include "data.h"
template <class T>
class Stack
{
public:
Stack():_current(NULL){}
void push(Data<T>* const);
Data<T>* pop();
private:
Data<T>* _current;
};
#endif;
stack.cpp :
#include "stack.h"
template <class T>
Data<T>* Stack<T>::pop()
{
if(this->_current == NULL)
{
cout << "Empty stack." <<endl;
return NULL;
}
else
{
Data<T>* tmpPtr = this->_current;
this->_current = this->_current->getPrev();
return tmpPtr;
}
}
template <class T>
void Stack<T>::push(Data<T>* const data)
{
if(this->_current == NULL) // Empty stack;
{
_current = data;
_current->setPrv(NULL);
}
else
{
Data<T>* tmpPtr = this->_current;
this->_current = data;
this->_current->setPrv(tmpPtr);
}
}
data.h
#ifndef DATA_H
#define DATA_H
template <class T>
class Data
{
public:
Data(T data):_data(data){}
T getData() const { return this->_data; }
void setPrv(Data* const prev){ this->_prev = prev; }
Data* getPrev() const { return this->_prev; }
private:
Data<T>* _prev;
T _data;
};
#endif
Put all the definitions of the template class functions in the .h. They basically aren't allowed to be in separate files.
This occurs becauses templates are not like typical classes. The compiler will generate a class for you off of your template instantiation. Because of this, the compiler will need to know where to lookup the function definitions, so put them inside the .h where the class is defined.
Template functions are not compiled until they're specialized(used), and your stack.cpp doesn't produce any machine code. Move them to stack.h

undefined reference with member functions using g++

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