destroying class having private destructor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Test{

private :
	int a;
	int *arr;
    ~Test(){};

public :
    Test(int i): a(i),arr(new int[100]) {}
    int geta()
    {
    	return a;
    }

    friend void destroy(Test *);
};

void destroy(Test *obj)
{
	delete [](obj->arr);
	obj->~Test();
}

int main ()
{
  Test *t= new Test(2);
  cout<< t->geta();
  
  destroy(t);

 return 0;
}



Is my code correct
? I mean any logical error or memory leak?

Is there any need of calling obj->~Test() ?

Are there any other standard ways to destroy objects having private destructor?
Last edited on
Hi,

If you are worried about memory leaks, then consider using smart pointers - never use new or delete ever again.

Why do you have a private destructor?

Edit:

Sorry, I should have done this before posting ....

I just read up about private destructor's - it seems they are handy for reference counted objects - which is what smart pointers are, but you don't seem to be doing that.
Last edited on
private destructor are used to make only dynamic objects. Because the compiler can't invoke the destructor.

1
2
Test t(1)                   // fails
Test *t= new Test(1) // OK .. programmer himself has to destroy 
Your code leaks the Test object. This is because you destroy it (call the destructor) but you don't free the memory.
@dhayden
doesn't delete free the memory?
A private destructor doesn't make sense unless the constructors are also private. There's little value in being able to create an object if you can't destroy it. There might be a few very specific circumstances where you might want a private dtor, but frankly I can't think of any.

(Even reference counted objects work fine with a public dtor)

Is there any need of calling obj->~Test() ?


No. delete will automatically call dtors on all objects in the array. You must not call them explicitly... and instead, you should delete the object (since it was allocated with new):


1
2
3
4
void destroy(Test *obj)
{
	delete obj;
}


But even this might fail because now delete is calling your dtor instead of your destroy() friend function.


Really... just make the dtor public.
Last edited on
Is my code correct? I mean any logical error or memory leak?


==31132== HEAP SUMMARY:
==31132==     in use at exit: 16 bytes in 1 blocks
==31132==   total heap usage: 8 allocs, 7 frees, 676 bytes allocated
==31132== 
==31132== LEAK SUMMARY:
==31132==    definitely lost: 16 bytes in 1 blocks


specifically, the pointer t obtained from the new-expression at line 26, was never passed to a delete.
Last edited on
@Disch and @Cubbi

I have 1 more question:
Assume: destructor is Public.

1
2
3
4
~Test()
{
    delete[] arr;
}


Now, will the data member (created on stack like int a here) be also deleted?
I have written my own destructor, so compiler will not define it for me.

@Cubbi
offtopic, but how did you find out the HEAP SUMMARY?

It would be better if i debug code myself rather than asking here in future.
I ran your program through valgrind, on a Linux box.
> private destructor are used to make only dynamic objects. Because the compiler can't invoke the destructor.

This (public constructors and a private destructor) is what Scott Myers recommends.
Item 27: More Effective C++.
...
An alternative is to declare all the constructors private. The drawback to that idea is that a class often has many constructors, and the class's author must remember to declare each of them private. This includes the copy constructor, and it may include a default constructor, too, if these functions would otherwise be generated by compilers; compiler-generated functions are always public. As a result, it's easier to declare only the destructor private, because a class can have only one of those.
...


I've generally favoured the use of private constructors and a public destructor (in conjunction with public, static factory functions or a helper friend factory class) to exercise control over how clients create objects. It makes the task of the class author a bit harder; but it also provides finer control (for instance, the class author can enforce use of smart pointers).

For instance:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <memory>
#include <iostream>

struct A final
{
    ~A() { std::cout << "A::destructor\n" ; /* .. */ }; // destructor is public

    // static factory functions to create dynamically allocated objects
    template < typename... ARGS > static std::unique_ptr<A> make_unique( ARGS&&... args )
    { return std::unique_ptr<A>( make_new( std::forward<ARGS>(args)...  ) ) ; }

    template < typename... ARGS > static std::shared_ptr<A> make_shared( ARGS&&... args )
    { return std::shared_ptr<A>( make_new( std::forward<ARGS>(args)... ) ) ; }

    // ...

    private:
        // all constructors are private
        A( /* ... */ ) { /* ... */ }
        A( int /* ... */ ) { /* ... */ } // another constructor
        A( const A& ) { /* ... */ }
        A( A&& ) noexcept = default ;

        // ...

        template < typename... ARGS > static A* make_new( ARGS&&... args )
        { return new A( std::forward<ARGS>(args)... ) ; }

        // ....
};

int main()
{
    auto p = A::make_unique( 200 /* ... */ ) ;
    auto p1 = A::make_shared(*p) ;
    // etc.
}

http://coliru.stacked-crooked.com/a/0c3c0acd7715361a
I have 1 more question:
Assume: destructor is Public.

1
2
3
4
~Test()
{
    delete[] arr;
}


Now, will the data member (created on stack like int a here) be also deleted?


If you change your main to match then the memory will get cleaned up just fine:
1
2
3
4
5
6
7
int main ()
{
  Test *t= new Test(2);
  cout<< t->geta();
  delete(t);
  return 0;
}

Line 5 calls the destructor, which deletes the arr array allocated in the constructor. Delete then frees the memory allocated to the t object itself at line 3. Note that in this case there is nothing on the stack because you specifically allocated t on the heap at line 3.
Topic archived. No new replies allowed.