malloc是一个C函数,对类、构造函数等一无所知。
如果您对使用它一无所知,您将必须始终在每个对象上调用放置new(注意:这需要包括标题<new>),并且在释放之前手动调用析构函数。您还需要存储从位置 new 返回的指针,以避免未定义的行为(因为从技术上讲,这是唯一指向对象生命周期开始的指针)。
正如您在编辑中所做的那样,它看起来像:
auto cls = static_cast<MyClass*>(std::malloc(sizeof(MyClass)));
cls = new(cls) MyClass(/* any arguments here ... */);
cls->value = "hello";
cls->~MyClass();
std::free(cls);
但是,请注意,使用malloc 实际上会引入与异常安全 相关的其他问题。如果您的placement-new 调用引发异常,std::malloc 分配的内存将泄漏——这很糟糕。如果malloc 返回null,您也不希望放置new 在nullptr 上运行,并且需要传达此错误- 可能通过异常。您可能希望将其包装到一个帮助程序中,以确保这些情况不会发生:
#include <new> // placement-new, std::bad_alloc
#include <utility> // std::forward
#include <cstdlib> // std::malloc, std::free
template <typename T, typename...Args>
T* make(Args&&...args)
{
auto* p = static_cast<T*>(std::malloc(sizeof(T)));
// Placement new can't operate on nullptr
if (p == nullptr) {
// alternatively, this could be 'return nullptr' if not using exceptions
throw std::bad_alloc{};
}
try {
p = new (p) T(std::forward<Args>(args)...);
} catch (...) {
std::free(p);
throw; // rethrow the exception here
}
return p;
};
同样,您可能希望有一种方法在释放对象时销毁它们,以免资源泄漏:
template <typename T>
void dispose(T* p)
{
p->~T();
std::free(p);
}
使用这些实用程序,上面的示例现在变为:
auto cls = make<MyClass>(/* any arguments here ... */);
cls->value = "hello";
dispose(cls);
如果这看起来像一个非常多的样板,这是因为这正是 new 和 delete 已经为您所做的。如果可以,在处理 C++ 类型时使用这些工具会更好。这也使您可以轻松地继续使用其他 RAII 包装器,例如智能指针,而无需手动指定分配器 (shared_ptr) 或删除器 (unique_ptr)。
在使用 C++ 代码时,IMO 确实没有充分的理由阻止使用 new 和 delete 来支持 malloc/free。如果您有一个库,该库只公开了一个仅 C 接口,但在 C++ 代码中实现——实际上,最好将分配内部化并切换到 new 和 delete,而不是使用malloc 和free 这样您就可以省去麻烦。1
要注意的另一件事是,如果您系统中分配的类型通过alignas 自定义对齐超过alignof(std::max_align_t),则使用std::malloc 将是未定义的行为,因为它将无法满足对齐要求。这是new/delete 会为您处理的另一件事。
1 如果您的“混合 C++/C”代码在某些时候暴露了 C 接口,那么使用 new 和 delete 而不是 malloc 会更干净,并简单地在您的 API 上显式公开创建/删除函数。例如:
// C header:
extern "C"
my_class* make_my_class(void);
extern "C"
void dispose_my_class(my_class* p);
// C++ implementation:
extern "C"
my_class* make_my_class(void)
{
return new my_class{ ... };
}
extern "C"
void dispose_my_class(my_class* p)
{
delete p;
}
这通常是 C/C++ 互操作所采用的方法。