What is this error message about implicitly deleted virtual destructors?
Asked Answered
A

1

17

I've just updated GCC from (I think) 4.5.6 to 4.6.1, under Windows, MinGW. Suddenly my NonInstantiable base class (from which you inherit with public virtual to prevent instantiation) refuses to work with the following and similar error messages:

#ifndef Frigo_Lang_NonInstantiable
#define Frigo_Lang_NonInstantiable

namespace Frigo
{
namespace Lang
{

/**
*   Inherit from this class if you want to make a non-instantiable class. Most
*   useful for static classes. It seems every inheritance combination
*   (public/protected/private, non-virtual/virtual) shuts off instantiation in
*   all subclasses as well.
**/

class NonInstantiable
{
private:
/*  Private Classes  */

    /**
    *   A dummy class to prevent GCC warnings about virtual
    *   constructors/destructors and no friends
    **/
    class NonInstantiableDummy { };

/*  Private Constructors  */

    /**
    *   Private constructor to prevent instantiation
    **/
    NonInstantiable() { }

    /**
    *   Private destructor to prevent instantiation on the stack. Virtual to
    *   prevent GCC warnings
    **/
    virtual ~NonInstantiable() { }

/*  Friends  */
    friend class NonInstantiableDummy;
};

}
}

#endif

Errors:

/code/Frigo/Util/Arrays:40:7: error: deleted function 'virtual Frigo::Util::Arrays::~Arrays()'
/code/Frigo/Lang/Object:37:11: error: overriding non-deleted function 'virtual Frigo::Lang::Object::~Object()'
/code/Frigo/Util/Arrays:40:7: error: 'virtual Frigo::Util::Arrays::~Arrays()' is implicitly deleted because the default definition would be ill-formed:
/code/Frigo/Lang/NonInstantiable:39:11: error: 'virtual Frigo::Lang::NonInstantiable::~NonInstantiable()' is private
/code/Frigo/Util/Arrays:40:7: error: within this context
/code/Frigo/Lang/NonInstantiable:39:11: error: 'virtual Frigo::Lang::NonInstantiable::~NonInstantiable()' is private
/code/Frigo/Util/Arrays:40:7: error: within this context
/code/Frigo/Util/Arrays:40:7: error: deleted function 'virtual Frigo::Util::Arrays::~Arrays()'
/code/Frigo/Lang/NonInstantiable:39:11: error: overriding non-deleted function 'virtual Frigo::Lang::NonInstantiable::~NonInstantiable()'

I suspect it is because I do not create any destructors, virtual or otherwise, in the child classes, and this somehow conflicts with the private virtual destructor of NonInstantiable, but I need confirmation. And a solution how to fix my NonInstantiable class to suppress these errors, but still work.

Albric answered 28/9, 2011 at 17:28 Comment(6)
A private destructor, thats seems just mean to me. Care to explain you comments in your code from the link? Edit: Mark B's answer explains it.Tula
Well, the class tries to prevent instantiation (in subclasses as well) by declaring a private constructor and destructor. The destructor needs to be virtual otherwise GCC whines at inheritance. The friend inner class need to be there as well otherwise GCC whines.Albric
What is your use-case? Why do you need this? I'm very curious.Tula
Just to prevent accidental instantiation of static classes (aka "storage classes" aka "utility classes"). There is some static keyword to mark such classes, but IIRC it allows only static methods, it throws a fit when it sees a static variable.Albric
@Frigo: in C++, you'd usually use a namespace for that, and only define a class when you actually want an instantiable type. "Static classes" only make sense in languages that force you to put everything in a class.Nahuatl
Sometimes I need static variables and methods that are private (for example, the internals of Arrays::quicksort). Namespace scope variables and methods are not perfect, they are accessible by everyone and this can cause complications. I prefer them being in classes. Anonymous namespaces help the situation somewhat, but their advantages are negligible.Albric
R
26

Parent destructors always need to be callable from a child class (because this happens automatically) and so parent class destructors can't be private.

Just make your NonInstantiable's destructor protected.

Also note that a child class could circumvent the parent as written by explicitly (accidentally?) calling into its public compiler-generated copy constructor.

EDIT: I should add as an aside that you might want to consider your need for a non-instantiable class here. I personally believe that a combination of free functions and anonymous-namespace variables would be a cleaner way of doing this.

Raychel answered 28/9, 2011 at 17:32 Comment(1)
Good call at making the destructor private. Is this due to some recent language change part of C++11 or just a GCC bugfix to better conform? Also, created a private copy constructor as well just to be sure ;)Albric

© 2022 - 2024 — McMap. All rights reserved.