9

I have seen code where the constructor has been declared as private while the destructor is public. What is the use of such a declaration? Is the destructor required to be public so that during inheritance the calls can be possible or is it a bug in the code?

The question might seem to be a bit short on information, but what I really want to know is if having a public destructor when the constructor is required to be private abides by the C++ rules?

Mat
  • 202,337
  • 40
  • 393
  • 406
Sankalp
  • 2,796
  • 3
  • 30
  • 43
  • 1
    A class only has one destructor, but it has several constructors (default, copy, move (since C++11), and possibly more user-defined). In the code you have seen, were _all_ constructors declared private? Also, were they given a definition or left undefined? Also, you mentioned inheritance: was the class a base class? (You can add a code snippet to your question for illustration) – gx_ Aug 31 '13 at 08:24
  • The constructors were all private; default constructor has been given a definition. I think I'll not be able to provide the code snippet as it's an industry code, but, I think the information in the question suffices. – Sankalp Aug 31 '13 at 08:27
  • how exactly would you "inherit" from a base class where you don't have at least *protected* access to a constructor of that base? Regarding why someone would make a constructor private, one common scenario is a singleton model class (ugh, dirty word, that singleton). A static class variable is declared of the same class type. It can construct, but no one else can. – WhozCraig Aug 31 '13 at 08:31
  • Regarding whether a private destructor is allowed I don't suppose [this helps explain it](http://stackoverflow.com/questions/631783/what-is-the-use-of-having-destructor-as-private) – WhozCraig Aug 31 '13 at 08:37
  • (As for "industry code", it's ok to make up a simplified example (with names like "Foo" and snipped implementation) when it's just for illustration, but whatever.) Looking at how the class is actually _used_ (how external code gets an instance (or a pointer to one), where destruction is triggered), not only at its definition, may also help you understand the why. – gx_ Aug 31 '13 at 09:07

6 Answers6

9

Short Answer

Creating a constructor as private but the destructor as public has many practical uses.

You can use this paradigm to:

Long Answer

Above I hinted that you can use private constructors and destructors to implement several design patterns. Well, here's how...

Reference Counting

Using private destructor within an object lends itself to a reference counting system. This lets the developer have stronger control of an objects lifetime.

class MyReferenceObject
{
public:
    static MyReferenceObject* Create()
    {
        return new MyReferenceObject();
    }

    void retain()
    {
        m_ref_count++;
    }

    void release()
    {
        m_ref_count--;
        if (m_ref_count <= 0)
        {
            // Perform any resource/sub object cleanup.
            // Delete myself.
            delete this; // Dangerous example but demonstrates the principle.
        }
    }
private:

    int m_ref_count;

    MyReferenceObject()
    {
        m_ref_count = 1;
    }

    ~MyReferenceObject() { }

}

int main()
{
    new MyReferenceObject(); // Illegal.
    MyReferenceObject object; // Illegal, cannot be made on stack as destructor is private.

    MyReferenceObject* object = MyReferenceObject::Create(); // Creates a new instance of 'MyReferenceObject' with reference count.
    object->retain(); // Reference count of 2.
    object->release(); // Reference count of 1.
    object->release(); // Reference count of 0, object deletes itself from the heap.
}

This demonstrates how an object can manage itself and prevent developers from corrupting the memory system. Note that this is a dangerous example as MyReferenceObject deletes itself, see here for a list of things to consider when doing this.

Singleton

A major advantage to private constructors and destructors within a singleton class is that enforces the user to use it in only the manner that the code was design. A rogue singleton object can't be created (because it's enforced at compile time) and the user can't delete the singleton instance (again, enforced at compile time).

For example:

class MySingleton
{
public:
     MySingleton* Instance()
     {
        static MySingleton* instance = NULL;
        if (!instance)
        {
            instance = new MySingleton();
        }

        return instance;
     }
private:
    MySingleton() { }
    ~MySingleton() { } 
}

int main()
{
     new MySingleton(); // Illegal
     delete MySingleton::Instance(); // Illegal.
}

See how it is almost impossible for the code to be misused. The proper use of the MySingleton is enforce at compile time, thus ensuring that developers must use MySingleton as intended.

Factory

Using private constructors within the factory design pattern is an important mechanism to enforce the use of only the factory to create objects.

For example:

class MyFactoryObject
{
public:

protected:
    friend class MyFactory; // Allows the object factory to create instances of MyFactoryObject

    MyFactoryObject() {} // Can only be created by itself or a friend class (MyFactory).
}

class MyFactory
{
public:
    static MyFactoryObject* MakeObject()
    {

        // You can perform any MyFactoryObject specific initialisation here and it will carry through to wherever the factory method is invoked.
        return new MyFactoryObject();
    }
}

int main()
{
    new MyFactoryObject(); // Illegal.
    MyFactory::MakeObject(); // Legal, enforces the developer to make MyFactoryObject only through MyFactory.
}

This is powerful as it hides the creation of MyFactoryObject from the developer. You can use the factory method to perform any initilisation for MyFactoryObject (eg: setting a GUID, registering into a DB) and anywhere the factory method is used, that initilisation code will also take place.

Summary

This is just a few examples of how you can use private constructors and destructors to enforce the correct use of your API. If you want to get tricky, you can combine all these design patterns as well ;)

matthewrdev
  • 11,930
  • 5
  • 52
  • 64
  • You have a bunch of errors in your examples, such as your Singleton::Instance() is returning a MySingleton by value, not by reference or pointer. Your declaration of the static instance variable has no type. Same with your MakeObject() method returning by value, but attempting to return a pointer. – Andre Kostur Aug 31 '13 at 16:45
  • Thanks for highlighting those. I'll fix the answer (I've been spending too much time in c# land). – matthewrdev Aug 31 '13 at 21:38
4

First thing: the destructor can be private.

having a public destructor when the constructor is required to be private abides by the C++ rules?

It's totally working in C++. In fact, a great example of this scenario is the singleton pattern, where the constructor is private and the destructor is public.

rustyMagnet
  • 3,479
  • 1
  • 31
  • 41
Hitesh Vaghani
  • 1,342
  • 12
  • 31
  • 1
    Exactly. Singleton was what I had in mind while asking this question. But, wherever `singleton` is explained, the destructor has been made private raising further doubts and questions. – Sankalp Aug 31 '13 at 08:39
2

In reverse order.

Is the destructor required to be public so that during inheritance the calls can be possible or is it a bug in the code?

Actually, for inheritance to work the destructor should be at least protected. If you inherit from a class with a private destructor, then no destructor can be generated for the derived class, which actually prevents instantiation (you can still use static methods and attributes).

What is the use of such declaration?

Note that even though the constructor is private, without further indication the class has a (default generated) public copy constructor and copy assignment operator. This pattern occurs frequently with:

  • the named constructor idiom
  • a factory

Example of named constructor idiom:

class Angle {
public:
    static Angle FromDegrees(double d);
    static Angle FromRadian(double d);

private:
    Angle(double x): _value(x) {}
    double _value;
};

Because it is ambiguous whether x should be precised in degrees or radians (or whatever), the constructor is made private and named method are provided. This way, usage makes units obvious:

Angle a = Angle::FromDegrees(360);
Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
1

You make constructor private if you want to prevent creating more then one instance of your class. That way you control the creation of intances not their destruction. Thus, the destructor may be public.

cpp
  • 3,743
  • 3
  • 24
  • 38
  • 1
    I would remove the first sentence completely since it's incorrect. – rbaleksandar Nov 21 '16 at 15:10
  • To elaborate on @rbaleksandar's comment, making the constructor private does not in itself prevent creating more than one instance of your class. You still need to do some work to make this happen. For example, you may need to write a static factory method that ensures that at most a single instance of the class is constructed. Making the constructor private will now force users to call the static method to obtain an instance. In addition, your answer leaves it unclear as to whether this is the only situation where you want to make the constructor private. It isn't. – Alan Feb 03 '17 at 19:37
0

One example in my head, let's say you want to limit the class instance number to be 0 or 1. For example, for some singleton class, you want the application can temprary destroy the object to rducue memory usage. to implement this constructor will be private, but destructor will be public. see following code snippet.

class SingletoneBigMemoryConsumer
{
private:
    SingletoneBigMemoryConsumer()
    {
        // Allocate a lot of resource here.
    }

public:
    static SingletoneBigMemoryConsumer* getInstance()
    { 
        if (instance != NULL) 
            return instance;
        else
            return new SingletoneBigMemoryConsumer();
    }
    ~SingletoneBigMemoryConsumer()
    {
        // release the allocated resource.
        instance = NULL;
    }
private:
    // data memeber.
    static SingletoneBigMemoryConsumer* instance;
}



//Usage.
SingletoneBigMemoryConsumer* obj = SingletoneBigMemoryConsumer::getInstance();
// You cannot create more SingletoneBigMemoryConsumer here.
// After 1 seconds usage, delete it to reduce memory usage.
delete obj;
// You can create an new one when needed later
ZijingWu
  • 3,350
  • 3
  • 25
  • 40
0

The owner of an object needs access to the destructor to destroy it. If the constuctors are private, there must be some accessible function to create an object. If that function transferes the ownership of the constructed object to the caller ( for example return a pointer to a object on the free store ) the caller must have the right to access the destructor when he decides to delete the object.