提问者:小点点

在强制转换的指针上调用虚函数会导致segfault[closed]


我需要手动分配代码中的对象,我的分配器使用void指针和偏移量,并在必要的地方强制转换它们。这应该不是一个问题(而且它在大多数情况下都能工作),但是当我调用一个虚函数时,我得到了一个分段错误。我假设这是因为指针没有指向vtable的指针,所以它从未初始化的内存中读取函数指针并试图调用它,这会导致segfault。但是,我希望能够使用虚拟函数。我怎样才能规避这个问题呢?

MVE(我的PC(x86_64)上的Segfaults在G++10.2.0时编译,没有标志):

#include <iostream>
#include <cstdlib>

struct BaseClass {
    virtual void do_stuff() = 0;
};

struct DerivedClass : public BaseClass {
    virtual void do_stuff() { std::cout << "i did it!" << std::endl; }
};

int main(int argc, char const* argv[]) {
    void* data = std::malloc(sizeof(DerivedClass));
    DerivedClass other;
    *((DerivedClass*)data) = other;
    // new (data) OtherClass; // this works fine, but why?
    ((BaseClass*)data)->do_stuff();
    return 0;
}

共2个答案

匿名用户

void* data = std::malloc(sizeof(DerivedClass));

null

((BaseClass*)data)->do_stuff();

正在将此强制转换为它不是的类型。

您需要实际创建您的派生类,例如:

auto data = new DerivedClass();

如果它必须来自某个错误的空间,你可以使用新的位置,例如:

auto data = new(buf) DerivedClass();

如果希望复制特定对象,编写复制构造函数会安全得多。

匿名用户

您可以使用placement new来初始化内存。

int main(int argc, char const* argv[])
{
    void* data = std::malloc(sizeof(DerivedClass));

    // This is placement new - it doesn't actually allocate memory
    DerivedClass *dc = new (data) DerivedClass();

    dc->do_stuff();

    // You need to call the destructor manually if you allocated the memory with placement new.
    // You can't safely use operator delete here
    dc->~DerivedClass();
    std::free(dc);

    return 0;
}

您还可以在您想要拥有自定义内存管理的类上覆盖操作符new和delete,然后像平常一样使用它们,这可能更容易,因为现在您不必担心手动删除它们。您可能还希望以类似的方式重写运算符new[]和运算符delete[]。

struct DerivedClass : public BaseClass
{
    virtual void do_stuff() { std::cout << "i did it!" << std::endl; }

    static void * operator new(size_t size) 
    { 
        return std::malloc(size); 
    }
  
    static void operator delete(void * p) 
    { 
        std::free(p); 
    }
};

int main(int argc, char const* argv[])
{
    DerivedClass *dc = new DerivedClass();
    dc->do_stuff();
    delete dc;
    return 0;
}

https://en.cppreference.com/W/cpp/memory/new/operator_new