Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I allocate an array of a class with deleted or private destructor? [duplicate]

I recently ran into this problem at work. A library I'm using makes use of reference counted objects and implements its own way of handling it. Part of the implementation is that each class of the library has a private destructor. Im guessing this is to prevent creation of objects on the stack as the library manages objects lifetime automatically (Its a scene graph).

Anyways, I wanted to allocate an array of such a class on the heap and ran into the following problem:

#include <iostream>

using namespace std;

    class test
    {
    public:
        test() {
            cout << "ctor" << endl;
        }

        //~test() = delete; also doesnt work

    private:
        ~test()
        {
            cout << "dtor" << endl;
        }

    };

    int main()
    {
        //works
        auto oneInstance = new test;

        //doesnt work
        auto manyInstances = new test[3];
    }

The array allocation produces the following error using GCC:

source_file.cpp: In function ‘int main()’:
source_file.cpp:15:5: error: ‘test::~test()’ is private
     ~test()
     ^
source_file.cpp:26:36: error: within this context
     auto manyInstances = new test[3];
                                    ^

Why does the destructor need to be public/available in order to allocate an array of this class on the heap? It works fine when only allocating a single instance like in the line before. I also tried using the more modern "delete" syntax, but it produced the same result.

Is there any kind of magic in the new[] operator that I'm not aware of?

EDIT:

Thanks for the quick help. Im wondering why this code doesnt print "dtor" twice though:

#include <iostream>

using namespace std;

class test
{
public:
    test() {
        static int allocations = 0;
        ++allocations;

        if(allocations == 3)
        {
            //produce exception
            throw 1;
        }
        cout << "ctor" << endl;
    }

    ~test()
    {
        cout << "dtor" << endl;
    }

};

int main()
{
    //works
    auto oneInstance = new test;

    //doesnt work
    try {
    auto manyInstances = new test[3];
    }
    catch(...)
    {
            cout << "error?";
    }
}

This prints:

ctor ctor dtor error?
like image 925
Mille25 Avatar asked Jun 27 '17 06:06

Mille25


People also ask

Does delete [] call destructor?

Yes, delete[] guarantees destructors are called on every object.

What happens when a destructor is private?

When something is created using dynamic memory allocation, it is the programmer's responsibility to delete it. So compiler doesn't bother. In the case where the destructor is declared private, an instance of the class can also be created using the malloc() function.

Can we have multiple destructors in a class?

Can there be more than one destructor in a class? No, there can only one destructor in a class with classname preceded by ~, no parameters and no return type.

Can we declared destructor in private section?

Yes, destructor can be private and it is not true that class cannot be instantiated.

When is it the programmer's responsibility to delete an array?

Whenever an array of the object of a class is created at runtime then it is the programmer’s responsibility to delete it and avoid a memory leak: Constructor is called! Constructor is called! Constructor is called! Writing! Writing! Writing! Destructor is called! Destructor is called! Destructor is called!

How to delete an object from a class in C++?

In C++, the single object of the class which is created at runtime using a new operator is deleted by using the delete operator, while the array of objects is deleted using the delete [] operator so that it cannot lead to a memory leak. Writing code in comment? Please use ide.geeksforgeeks.org , generate link and share the link here.

Why can't I copy an object from one class to another?

Assuming your class is next to trivial, the reason for the error could be that two of your NameClass objects have an array pointer that points to the same array. This can happen if your class does not have a user-defined copy constructor and/or assignment operator, in which case the compiler will generate one for you.


1 Answers

It's because of exceptions, the array version of new[] has to go and call the destructor on elements that have been previously allocated when an exception propagates to ensure exception safety. The single element new does not need to do that. If allocation fails, it just fails, no need to destroy anything.

§ 8.3.4 New [expr.new/20]

If the new-expression creates an array of objects of class type, the destructor is potentially invoked


Regarding your edit, see the following quote from the C++17 standard

§ 8.17 Throwing an exception [expr.throw/4]

If no exception is presently being handled, evaluating a throw-expression with no operand calls std::terminate()


Regarding your second edit, you have missed counting an instance of test that you created via new (not new[]), that leads to the first instance of test being created, that's where the confusion about number of constructions comes from.

like image 105
Curious Avatar answered Oct 12 '22 18:10

Curious