Why is this trying to find the destructor twice?
Asked Answered
F

1

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
Fulminate answered 16/10, 2014 at 23:25 Comment(9)
_GENERATEMPLATE_H_ is a reserved identifier. You should also check with GCC to see what it did to the code so you can match up the given locations.Davide
I am getting only one unidentified reference to destructor (both clang++ and g++4.9.1, OS X 10.9)Korenblat
Oops! Should have used GENERALTEMPLATE_H. But changing that doesnot change the error.Fulminate
@Fulminate what compiler/platform are you using?Korenblat
@Korenblat gcc version 4.4.6 20120305 (Red Hat 4.4.6-4) (GCC)Fulminate
<codereview>It seems to me that #include <iostream> is not needed in your header.</codereview>Almatadema
@toutnom, what happens if you comment out the call to arbitraryFunction(2.3);?Korenblat
@vsoftco, commenting out call to arbitraryFunction gives linking error for only one destructor!Fulminate
@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.Korenblat
J
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.

Jareb answered 16/10, 2014 at 23:36 Comment(3)
Sounds reasonable to me.Almatadema
@Snefdel,@vsoftco: Just asserting what you said! Using "template <class M> void arbitraryFunction(const M &m) throw();" leads to only one destructor error instead of two. So, problem is definitely related to throwing exception. Thanks!Fulminate
@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.Korenblat

© 2022 - 2024 — McMap. All rights reserved.