6

I was trying out the following piece of code:

GeneralTemplate.h

#ifndef _GENERATEMPLATE_H_
#define _GENERATEMPLATE_H_

#include <iostream>

template <class T>
class GeneralTemplate
{
  public:
  GeneralTemplate();
  GeneralTemplate(const GeneralTemplate &g);
  
  ~GeneralTemplate();
  
  GeneralTemplate& operator= (GeneralTemplate const& g);
  
  template <class M>
  void arbitraryFunction(const M &m);
};

#endif

main.cpp

#include "GeneralTemplate.h"

#include <iostream>

int main()
{
    GeneralTemplate<int> gInt;
    gInt.arbitraryFunction(2.3);
    return 0;
}

Note that I don't have any implementation for the member functions of the class template. But that is not the problem. I know how to do that! If I try to compile main.cpp, I should get a linking error and that's what I get. The question is why is it trying to find the destructor twice (last two lines of error below).

$g++ main.cpp 
/tmp/cckrdPCs.o: In function `main':
main.cpp:(.text+0x13): undefined reference to `GeneralTemplate<int>::GeneralTemplate()'
main.cpp:(.text+0x34): undefined reference to `void GeneralTemplate<int>::arbitraryFunction<double>(double const&)'
main.cpp:(.text+0x45): undefined reference to `GeneralTemplate<int>::~GeneralTemplate()'
main.cpp:(.text+0x61): undefined reference to `GeneralTemplate<int>::~GeneralTemplate()'
collect2: ld returned 1 exit status
Community
  • 1
  • 1
toutnom
  • 244
  • 1
  • 7
  • `_GENERATEMPLATE_H_` is a [reserved identifier](http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier). You should also check with GCC to see what it did to the code so you can match up the given locations. – chris Oct 16 '14 at 23:27
  • I am getting only one unidentified reference to destructor (both clang++ and g++4.9.1, OS X 10.9) – vsoftco Oct 16 '14 at 23:29
  • Oops! Should have used _GENERALTEMPLATE_H_. But changing that doesnot change the error. – toutnom Oct 16 '14 at 23:30
  • @toutnom what compiler/platform are you using? – vsoftco Oct 16 '14 at 23:33
  • @vsoftco gcc version 4.4.6 20120305 (Red Hat 4.4.6-4) (GCC) – toutnom Oct 16 '14 at 23:36
  • ``It seems to me that `#include ` is not needed in your header.`` – Lightness Races in Orbit Oct 16 '14 at 23:36
  • @toutnom, what happens if you comment out the call to `arbitraryFunction(2.3);`? – vsoftco Oct 16 '14 at 23:37
  • @vsoftco, commenting out call to arbitraryFunction gives linking error for only one destructor! – toutnom Oct 16 '14 at 23:40
  • 3
    @toutnom, then I think @Snefel and @AndreyT got it right! (PS: can mark the function with `throw()` (or `noexcept` in C++11), and still probably have the same behaviour, i.e. no more than 1 dtor call. – vsoftco Oct 16 '14 at 23:41

1 Answers1

8

It's most likely related to exception safety. If arbitraryFunction throws an exception, the stack needs to be unwound, meaning gInt needs to be destroyed early. Since this is all happening in main, where no further unwinding is ever going to happen, it's doubtful whether it really needs two calls to the destructor.... but the behavior you're observing is not entirely off the wall.

Sneftel
  • 40,271
  • 12
  • 71
  • 104
  • Sounds reasonable to me. – Lightness Races in Orbit Oct 16 '14 at 23:36
  • @Snefdel,@vsoftco: Just asserting what you said! Using "template void arbitraryFunction(const M &m) throw();" leads to only one destructor error instead of two. So, problem is definitely related to throwing exception. Thanks! – toutnom Oct 17 '14 at 00:39
  • 2
    @toutnom, you should then accept Sneftel's answer, as it provides the correct answer and settles the question. This is a good practice on SO, after you wait a bit for good answers. – vsoftco Oct 17 '14 at 21:17