我试图定义一个只能在堆上实例化的类

时间:2018-08-08 12:30:19

标签: c++ visual-studio

我正在尝试通过将delete运算符作为朋友函数重载来实现此目的。代码如下:

#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;
}

以上代码在Visual Studio中显示错误“错误C2248'HeapOnly ::〜HeapOnly':无法访问在类'HeapOnly中声明的私有成员”

我不明白为什么它会出错,因为删除操作符作为朋友函数被重载,因此它应该能够访问私有的析构函数。

2 个答案:

答案 0 :(得分:2)

为什么尝试失败,请参见其他答案。我不知道是否可以以及是否可以实现只能在堆上实例化的类的一般目标,并且这是否可取,但是我对此表示怀疑。

但是,您可以做的是限制取消分配通过std::allocatorstd::default_delete进行,这样就不可能使用简单的自动变量:

#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; }); 
}

但是请注意,很多事情都依赖于自动变量,包括std::swapstd::sort(直接与std::sort交往无济于事,因为它将工作委托给特定于实现的助手例程)。但是,您可以启用unique_ptr(和shared_ptr),这似乎与仅使用堆的类很自然,然后对指向的对象进行排序。

进一步注意,即使上面的代码可能适用于大多数(即使不是全部)STL实现,但不能保证std::allocator<>::destroy()例如可以将销毁委托给助手函数,该助手函数是实现细节,因此不能成为朋友。

但是,您可以对此进行测试,并使用SFINAE规避此类情况。

答案 1 :(得分:1)

实际上并没有让您重载的“删除运算符”。有:

  • 删除表达式,如src中所示;和
  • 解除分配功能,用于释放内存,其语法令人困惑,delete abc

换句话说,您从未重载不存在的“删除运算符”或将其声明为朋友。重载并声明为朋友的唯一东西是 deallocation函数

删除表达式分两步进行操作:

  1. 调用析构函数以将对象还原到原始内存中
  2. 调用释放函数以释放内存

因此,私有析构函数仍被视为不是该类的朋友的operator delete直接调用。

我们可以做一些实验来验证:

代码1:不带main声明:https://godbolt.org/g/WVmzNP

friend

代码2:将class HeapOnly { int x; int y; ~HeapOnly() = default; }; int main() { HeapOnly *abc = new HeapOnly(); delete abc; } 声明为朋友:https://godbolt.org/g/9PVZ4C

main