Reputation: 39
I am trying to achieve this by overloading the delete operator as a friend function. The code is as follows:
#include <iostream>
class HeapOnly
{
int x;
int y;
~HeapOnly()
{
}
public:
void friend operator delete(void* a);
};
void operator delete(void* p)
{
delete p;
}
int main()
{
HeapOnly *abc = new HeapOnly();
delete abc;
}
The above code gives error in Visual Studio "Error C2248 'HeapOnly::~HeapOnly': cannot access private member declared in class 'HeapOnly"
I do not understand as to why it is giving error as the delete operator is overloaded as friend function hence it should be able to access the destructor which is in private.
Upvotes: 0
Views: 130
Reputation: 45424
As why your attempt failed, see other answers. I don't know whether, and if so how, you can achieve the general goal of a class that can only be instantiated on the heap and if this is desirable, but I doubt both.
However, what you can do is to restrict de-allocation to go through std::allocator
or std::default_delete
, so that simple automatic variables are not possible:
#include <iostream>
#include <memory>
#include <vector>
#include <algorithm>
class HeapOnly
{
~HeapOnly();
public:
bool operator < (HeapOnly const&) const;
friend class std::allocator<HeapOnly>;
friend class std::default_delete<HeapOnly>;
};
int main()
{
std::vector<HeapOnly> X(10); // okay
HeapOnly Y; // ERROR: cannot be destructed
std::sort(X.begin(),X.end()); // ERROR: requires automatic variables
std::vector<std::unique_ptr<HeapOnly>> Z(10); // okay
for(auto&z:Z)
z.reset(new HeapOnly);
std::sort(Z.begin(),Z.end(),[](std::unique_ptr<HeapOnly> const&x,
std::unique_ptr<HeapOnly> const&y)
{ return *x < *y; });
}
Note, however, that many things rely on automatic variables, including std::swap
and std::sort
(befriending std::sort
directly does not help, as it delegates the work to implementation-specific helper routines). However, you can enable unique_ptr
(and shared_ptr
), which appears the natural thing to do with a heap-only class, and sort the objects pointed to.
Note further that even though the code above may work with most if not all STL implementations, this is not guaranteed. std::allocator<>::destroy()
may, for example, delegate the destruction to a helper function, which is an implementation detail and hence cannot be befriended.
However, you could test for this and use SFINAE to dodge such cases.
Upvotes: 2
Reputation:
There isn't really a "delete operator" for you to overload. There are:
delete abc
; andoperator delete
.In other words, you have never overloaded the non-existent "delete operator" or declaring it a friend. The only thing overloaded and declared a friend is the deallocation function.
The delete expression does thing in two steps:
Therefore, the private destructor is still considered invoked directly by main
, which is not a friend of the class.
We can do a little experiment to verify that:
Code 1: Without friend
declaration: https://godbolt.org/g/WVmzNP
class HeapOnly
{
int x;
int y;
~HeapOnly() = default;
};
int main()
{
HeapOnly *abc = new HeapOnly();
delete abc;
}
Code 2: Declaring main
as friend: https://godbolt.org/g/9PVZ4C
class HeapOnly
{
int x;
int y;
~HeapOnly() = default;
friend int main();
};
int main()
{
HeapOnly *abc = new HeapOnly();
delete abc;
}
Upvotes: 2