如何防止类被malloc化,只允许新的?

时间:2017-11-01 11:25:52

标签: c++ malloc new-operator

在某些情况下,我希望强制调用构造函数,该构造函数会在new中自动调用,而不是在malloc中调用(在这种情况下,我们必须使用placement new技术)。有没有办法让类只适用于new而不是malloc?

编辑:编译时间限制会更好(像往常一样,我猜)。

4 个答案:

答案 0 :(得分:5)

没有办法。 malloc基本上是无类型的 - 它只是分配一个字节缓冲区,你不能阻止它,就像你不能阻止某人将无类型指针强制转换为你的类型的指针一样。

无论如何,不要尝试! 正如达米安康威(probably)所说,你的代码应该防范墨菲,而不是马基雅维利:阻止用户犯下诚实的错误。但当他们故意决定搞乱这种类型系统时,他们就是独立的。你的问题根本就没有用例。不要在上面浪费资源。

答案 1 :(得分:1)

您可以为班级创建公共虚拟界面和工厂方法,并隐藏您的实施。这样,只能通过您提供的方法创建类。

公共标题:

struct MyInterface
{
    static MyInterface *create();
    virtual void member() = 0; 
};

私人模块:

class MyImplementation
{
public:
    MyImplementation();
    void member() override;
};

MyInterface *MyInterface::create()
{
    return new MyImplementation();
}

答案 2 :(得分:1)

不要把这个答案视为你应该做的事情,但如果真的需要它可能对你有用。

首先,在 glibc 中, malloc 被定义为弱符号,这意味着它可以被应用程序或共享库覆盖。

您可以在共享库中定义自己的malloc,它几乎没有任何内容(返回NULL)。然后使用LD_PRELOAD链接它。

void* malloc (size_t size)
{
   ...
   return NULL;
}

这将阻止malloc从分配内存。 现在有点棘手的情况。我们知道new operator实现可以在内部使用(并且通常都是)malloc来分配一些内存块。

现在,对于每个类,您必须重载new和delete运算符。内部实现需要另一个自定义malloc和免费实现,它将调用:

#include <stdlib.h>

extern void *__libc_malloc(size_t);
extern void __libc_free(void* ptr);

或类似的东西:

static void* malloc_internal(size_t s) {
    // Wrapper for standard library's 'malloc'.
    // The 'static' keyword forces all calls to malloc_internal() in this file to resolve
    // to this functions.
    void* (*origMalloc)(size_t) = dlsym(RTLD_NEXT,"__libc_malloc");
    return origMalloc(s);
 }

一般情况下我不推荐这样做,但如果你真的需要它,你可以试试。还要记住,如果错误地使用 __ libc_malloc __ libc_free 会导致内存损坏,

答案 3 :(得分:0)

<击> 如果您需要此类限制的原因是为了防止使用类的not valid实例,则可以引入成员变量并使用它来确定对象是否构造正确。

<击>
class A
{
enum { SpecialValue = 123 };
public: 
    A() : m_marker(SpecialValue)
    bool isValid() const { return m_marker == SpecialValue; }
    void doAction() { assert(isValid); ... }
private:
    int m_marker;
};

或,c++11或更高版本:

class A
{
public: 
    A() : m_marker(true)
    bool isValid() const { return m_marker; }
    void doAction() { assert(isValid); ... }
private:
    bool m_marker = false;

};

<击>