使用调试版本调用 C API 上的 delete 到 C++ 接口段错误

Calling delete on C API to C++ interface segfaults with debug build

我遇到了一个问题,我有一些包装 C++ class 的代码,如下所示:

C++:

class A
{
  A() {}
  ~A() {}
}

C 接口:

typedef struct c_a c_a;
void c_a_new(c_a * self)
{
  self = reinterpret_cast<c_a *>(new A());
}
void c_a_delete(c_a * self)
{
  delete reinterpret_cast<A*>(self);
}

C代码:

c_a * self;
c_a_new(self);
c_a_delete(self);

我正在使用 CMake 作为构建系统使用 gcc 进行构建。当 CMAKE_BUILD_TYPE 设置为 ReleaseRelWithDebInfo 时一切正常,但是当 c_a_delete(self); 设置为 Debug 时调用 c_a_delete(self); 时出现段错误。这似乎发生在我使用 C 接口的所有 classes 上。如果我注释掉 c_a_delete() 中的 delete 调用,它似乎可以解决这个问题。我想这可能会导致内存泄漏。编译器是否有可能优化发布版本中的内存使用或是否有其他事情发生?

您正在按值传递指针,而不是更新原始指针。使用 return 值或指向指针的指针。 (我还添加了一个额外的句柄 typedef 以使其与其他 C api 更加同步)

typedef struct c_a c_a, *a_handle;
void c_a_new(a_handle* self)
{
    *self = reinterpret_cast<a_handle>(new A());
}
void c_a_delete(a_handle self)
{
    delete reinterpret_cast<A*>(self);
}

然后调用

a_handle self;
c_a_new(&self);
c_a_delete(self);

或者只是return获得的指针:

typedef struct c_a c_a, *a_handle;
a_handle c_a_new(a_handle* self)
{
    return reinterpret_cast<a_handle>(new A());
}
void c_a_delete(a_handle self)
{
    delete reinterpret_cast<A*>(self);
}

并像这样使用它:

a_handle self = c_a_new();
c_a_delete(self);

如果您希望对 int 的修改在函数外部可见,一种方法是将指针传递给 int,例如:

void foo(int * i) {
  *i = 42;
}

因此以下成立:

int i = 1;
foo(&i);
assert(i == 42);

同样,如果你想对c_a *的修改在函数外可见,一种方法是传递一个指向它的指针,例如:

void c_a_new(c_a ** pself)
{
  *pself = new A;
}

并将其命名为

c_a * self = NULL;
c_a_new(&self);

恕我直言,设计明智的是 return 指针而不是通过指针传递它并更新它更好,即类似

c_a * c_a_new()
{
  return new (std::nothrow) A;
}