0

I've got an error message from the linker undefined reference to wrapper<char>::Free() when I call this function inside ~wrapper(). It appeared after I decided to rewrite the entire class into a template class.

Here the code,

wrapper.h

#include <iostream>
#ifndef WRAPPER_H
    #define WRAPPER_H
#define ALLOC_FAILED 3048

template <class T> struct wrapper
{
    T * data = nullptr;
    int dsize = 0;

    void Free();
    void Alloc(int s);
    void Copy(const wrapper<T> & other);

    wrapper(): data(nullptr), dsize(0){               }
    wrapper(int s)                    { Alloc(s);     }
    wrapper(const wrapper<T> & other) { Copy(other);  }
    ~wrapper()                        { Free();       }

    const wrapper<T> & operator = (const wrapper<T> & other){ Copy(other); return *this;}
};
#endif // WRAPPER_H

wrapper.cpp

#include "wrapper.h"
template <class T> void wrapper<T>::Free()
{
    if(data)
    {
        delete [] data;
        dsize = 0;
        data = nullptr;
    }
}
template <class T> void wrapper<T>::Alloc(int s)
{
    if(data) Free();
    data = new (std::nothrow) T[s];
    if(!data) throw ALLOC_FAILED;
    dsize = s;
}
template <class T> void wrapper<T>::Copy(const wrapper<T> & other)
{
    Alloc(other.dsize);
    for(int i = 0; i < this->dsize; i++) data[i] = other.data[i];
}

log :

||=== Build: Debug in wrapper (compiler: GNU GCC Compiler) ===|
obj\Debug\main.o||In function `ZN7wrapperIcED1Ev':|
wrapper.h|19|undefined reference to `wrapper<char>::Free()'|
||error: ld returned 1 exit status|
||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 1 second(s)) ===|

but the code worked just fine when the structure wasn't a template

wrapper.h

#include <iostream>
#ifndef WRAPPER_H
    #define WRAPPER_H
#define ALLOC_FAILED 3048

struct wrapper
{
    char * data = nullptr;
    int dsize = 0;

    void Free();
    void Alloc(int s);
    void Copy(const wrapper & other);

    wrapper(): data(nullptr), dsize(0){               }
    wrapper(int s)                    { Alloc(s);     }
    wrapper(const wrapper & other)    { Copy(other);  }
    ~wrapper()                        { Free();       }
    const wrapper & operator = (const wrapper & other){ Copy(other); return *this;}
};
#endif // WRAPPER_H

wrapper.cpp

#include "wrapper.h"

void wrapper::Free()
{
    if(data)
    {
        delete [] data;
        dsize = 0;
        data = nullptr;
    }
}
void wrapper::Alloc(int s)
{
    if(data) Free();
    data = new (std::nothrow) char[s];
    if(!data) throw ALLOC_FAILED;
    dsize = s;
}
void wrapper::Copy(const wrapper & other)
{
    Alloc(other.dsize);
    for(int i = 0; i < this->dsize; i++) data[i] = other.data[i];
}

Thank you for your answers.

Maelstrom
  • 9
  • 4
  • See also [Splitting templated C++ classes into .hpp/.cpp files--is it possible?](https://stackoverflow.com/q/1724036/2602718) – scohe001 Jan 22 '20 at 17:22
  • TL;DR of the dupe: Template code can't be split. It all needs to be in the header file. (not 100% true, but close enough for most people) – NathanOliver Jan 22 '20 at 17:22
  • Thank you! It fixed the problem indeed which is that each translation units (.cpp +.h) are made independently, if there is no explicit instantiation in wrapper.cpp file, no code is generated into its .obj file, then the linker can't find it for main.o calls. The solution is to implement the template where it is instantiated, either by defining it in the header file, or by anticipation by making an explicit instantiation in the .cpp implementation file, like this : "template class wrapper;" for each type used in other files. I should rename the question title. – Maelstrom Jan 27 '20 at 13:21

0 Answers0