如何防止通过“new”运算符分配类? (我想确保我的 RAII 类始终分配在堆栈上。)

问题描述 投票:0回答:5

我想确保我的 RAII 类始终分配在堆栈上。

如何防止通过“new”运算符分配类?

c++ operator-overloading c++-faq
5个回答
60
投票

您需要做的就是将类的 new 运算符声明为私有:

class X
{
    private: 
      // Prevent heap allocation
      void * operator new   (size_t);
      void * operator new[] (size_t);
      void   operator delete   (void *);
      void   operator delete[] (void*);

    // ...
    // The rest of the implementation for X
    // ...
};  

将“operator new”设为私有可有效防止类外部的代码使用“new”创建 X 的实例。

要完成此操作,您应该隐藏“operator delete”和两个运算符的数组版本。

从 C++11 开始,您还可以显式删除函数:

class X
{
// public, protected, private ... does not matter
    static void *operator new     (size_t) = delete;
    static void *operator new[]   (size_t) = delete;
    static void  operator delete  (void*)  = delete;
    static void  operator delete[](void*)  = delete;
};

相关问题: 是否可以阻止对象的堆栈分配并只允许使用“new”启动它?


7
投票

我不相信你的动机。

在免费商店中创建 RAII 课程有充分的理由。

例如,我有一个 RAII 锁类。我有一条通过代码的路径,只有在满足某些条件时才需要锁定(它是一个视频播放器,如果我加载并播放了视频,我只需要在渲染循环期间保持锁定;如果没有加载任何内容,我不需要它)。因此,在免费存储上创建锁(使用

unique_ptr
)的能力非常有用;它允许我使用相同的代码路径,无论我是否必须取出锁。

即像这样的:

unique_ptr<lock> l;
if(needs_lock)
{
    l.reset(new lock(mtx));
}
render();

如果我只能在堆栈上创建锁,我就做不到......


2
投票

@DrPizza:

你的观点很有趣。但请注意,在某些情况下 RAII 习惯用法不一定是可选的。

无论如何,也许解决你的困境的更好方法是向你的锁构造函数添加一个参数来指示是否需要锁。例如:

class optional_lock
{
    mutex& m;
    bool dolock;

public:
    optional_lock(mutex& m_, bool dolock_)
        : m(m_)
        , dolock(dolock_)
    {
        if (dolock) m.lock();
    }
    ~optional_lock()
    {
        if (dolock) m.unlock();
    }
};

然后你可以写:

optional_lock l(mtx, needs_lock);
render(); 

0
投票

在我的特殊情况下,如果不需要锁,则互斥体甚至不存在,所以我认为这种方法会更难适应。

我想我真正难以理解的是禁止在免费商店上创建这些对象的理由。


0
投票

我的脑海中出现了一个问题,删除的静态 new/delete 运算符是否也会阻止分配派生类。

答案(是)现在似乎很明显,这些方法由派生类继承,因此也在那里被删除。

派生类可以添加自己的非删除 new/delete 运算符的定义,在这种情况下,派生类可以被分配。

© www.soinside.com 2019 - 2024. All rights reserved.