4

EDIT: Apparently the question is not clearly formulated enough. The issue I am having is that when the destructor is defined in the header it gets added into multiple .obj files and the linker complains. The actual question is:

When I add the destructor to a CPP file in a DLL project and use the dll with dynamic loading and the interface header file, does the base destructor still get called to prevent leaking memory?

I am using MSVC 10.0 and have a DLL project that implements an interface. The interface is an abstract (pure virtual) base class. The idea is that the header is used with dynamic loading of the library. Therefore, I have used a pure virtual destructor to make sure the destructor in the base class gets called. Here is sample code to explain this:

//ISplitter.h
#pragma once

struct param {
    int something;
}

class ISplitter {
public:
    virtual ~ISplitter() = 0;
    virtual void useful() = 0;
}

ISplitter::~ISplitter() {
    /* Make sure base class destructor gets called */
}

And the main implementation header

//CSplitter.h
#pragma once
#include "CHelper.h"
#include "ISplitter.h"


class CSplitter : public ISplitter {
private:
    CHelper hlp;
public:
    ~CSplitter();
    void useful();
}

Some helper class

//CHelper.h
#pragma once
#include "ISplitter.h" // I need the struct

// Class definition should go here but is irrelevant

Now the problem is that the linker generates an error that tells me the destructor: ISplitter::~ISplitter(void) has been multiply declared and the system will not build. Error:

CHelper.obj : error LNK2005: "public: virtual __cdecl ISplitter::~ISplitter(void)" (??1ISplitter@@UEAA@XZ) already defined in CSplitter.obj

What is the correct way to fix this? I have placed the destructor in ISplitter.cpp, but I am worried this may not work if I dynamically load the library and upcast the base class to ISplitter.

Wouter Simons
  • 2,856
  • 1
  • 19
  • 15
  • 3
    Please post real code. And the answer is to move the destructor definition to a.cpp file. –  May 30 '11 at 09:58
  • possible duplicate of [Pure virtual destructor in C++](http://stackoverflow.com/questions/630950/pure-virtual-destructor-in-c) – Björn Pollex May 30 '11 at 10:01
  • @Neil: Or to make the destructor not pure virtual in the first place. Why not just an empty virtual destructor? – Björn Pollex May 30 '11 at 10:03
  • @Wouter We don't need to see the original code, but we do need to see real C++ code that illustrates the problem. For example, here `ISplitter::ISplitter()` I assume there is a missing `~`? –  May 30 '11 at 10:07
  • @Neil: I apologize, it is missing that and that is a critical error. Apologies and fixed. – Wouter Simons May 30 '11 at 10:13
  • If you define a function, destructor or not, in a header you must make it `inline`. That solves the multiple definition problem. – Bo Persson May 30 '11 at 12:35

2 Answers2

6

The problem is that the base class destructor always gets called- but in this case, you've made it pure virtual, so it doesn't exist. The only reason to make a destructor pure virtual to is to enforce a class to be abstract when you have no other members. The destructor of a class needs to be defined in all cases.

Edit: I mis-read your code. Just define the destructor virtually inline.

virtual ~ISplitter() {}

There's no need for any pure virtual here, since you already have other pure virtual members.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • It does exist, hence the multiple-definition errors, though this is not obvious from his "pseudocode". –  May 30 '11 at 10:03
  • I believe that is what I prefer, much cleaner and I am sure that it will always be there. So I am accepting this answer. – Wouter Simons May 30 '11 at 10:37
  • 1
    +1 for "Just define the destructor inline", except I can't vote yet. He could also make the definition inline by qualifying the out-of-line definition of the destructor with inline. – David Hammen May 30 '11 at 12:13
  • I think the inline keyword is handled differently based on optimization settings – Wouter Simons May 30 '11 at 12:47
  • @WouterSimons the `inline` keyword mostly means "silently discard if this is defined in more than one compilation unit" (with some extra stuff about address-of), and member functions in `class` or `struct` bodies are implicitly `inline`. Under the C++ standard, it doesn't have much to do with inlining methods. – Yakk - Adam Nevraumont Jan 31 '13 at 19:28
4

Sharptooth's answers is correct in that you HAVE to provide a definition to the pure virtual destructor (see this GotW). But it is wrong in that you cannot write

virtual ~A() = 0 {};

according to this clause in the standard (although many compilers support this extension)

Clause 10.4 paragraph 2 of C++03 tells us what an abstract class is and, as a side note, the following:

[Note: a function declaration cannot provide both a pure-specifier and a definition —end note] [Example:

struct C {
virtual void f() = 0 { }; // ill-formed
};

—end example]

See this question of mine for more details

Community
  • 1
  • 1
Armen Tsirunyan
  • 130,161
  • 59
  • 324
  • 434