我可以在 C 中 free() 一些已经在 C++ 中 malloc() 过的东西吗?

mor*_*son 4 c c++ malloc free language-lawyer

我正在为用 C++ 编写的库编写一个包装器,以便可以从 C 中使用它。在包装器代码中,我制作了 C++ 容器底层数据的大量副本。例如,如果 c++ 库函数返回 a std::vector<int>,我的包装器将返回 形式的结构{size_t len; size_t size; void *arr;},其中arr包含向量中数据的副本。当用户使用完数据后,他们必须释放它。

我的问题是:用户(C 代码)调用C++ 中已 :d 的指针总是合法的吗?或者我必须在包装器代码中创建等效函数吗?free()malloc()

Jan*_*tke 5

您可以混合使用 C++std::malloc和 Cfree

std::mallocC++ 中的定义<cstdlib>据说与 C 中具有相同的内容和含义<stdlib.h>(有一些变化,例如命名空间)。此外,[c.malloc]说:

void* aligned_alloc(size_t alignment, size_t size);
void* calloc(size_t nmemb, size_t size);
void* malloc(size_t size);
void* realloc(void* ptr, size_t size);
Run Code Online (Sandbox Code Playgroud)

效果:这些函数具有 C 标准库中指定的语义。

这意味着您可以std::malloc在 C++ 中分配一些内存,并将其传递给某个调用free.


注意:混合不同的标准库或混合同一标准库的不同构建(调试/发布)可能仍然是一个问题,但这适用于所有语言功能。

C++标准库不使用std::malloc

话虽如此,使用像您建议的free那样分配的内存是不安全的。默认情况下,std::vector所有进行内存分配的容器都使用.std::allocatoroperator new

即使获取和释放内存的底层操作系统函数是相同的,混合new和也是未定义的行为。free

如何std::vector在C中使用

// C23
struct vector {
    // note: 3 pointers in size is usually the bare minimum which is needed for
    //       a std::vector.
    alignas(void*) unsigned char data[3 * sizeof(void*)];
};

// Note the symmetric interface; it doesn't matter how init/destroy are
// implemented to the user.
void vector_init(struct vector*);
void vector_destroy(struct vector*);
// Also add this and other functions to make the vector useful.
void vector_push(struct vector*, int element);

int main() {
    vector v;
    vector_init(&v); // no malloc, no free
    vector_push(&v, 42);
    vector_destroy(&v);
}
Run Code Online (Sandbox Code Playgroud)

到目前为止,我们基本上只是定义了struct vector包含一定数量的字节的 a 和三个不透明函数。所有代码都是C23兼容的,我们可以用C++实现实际的功能。

// C++20
static_assert(alignof(vector::data) >= alignof(std::vector));
static_assert(sizeof(vector::data) >= sizeof(std::vector));

extern "C" void vector_init(vector* v) {
    std::construct_at(reinterpret_cast<std::vector<int>*>(v->data));
}

extern "C" void vector_destroy(vector* v) {
    std::destroy_at(reinterpret_cast<std::vector<int>*>(v->data));
}

extern "C" void vector_push(vector* v, int element) {
    auto* vec = std::launder(reinterpret_cast<std::vector<int>*>(v->data));
    vec->push_back(element);
}
Run Code Online (Sandbox Code Playgroud)

C++ 端使用std::construct_at(或者在 C++20 之前,您可以使用新的放置)。std::vector我们在 的原始字节中创建一个vector::data。请注意,我们没有在这段代码中 调用newdeletemalloc或。仍然负责所有的内存管理。freestd::vector