在 C++ 中调用未初始化内存的构造函数
Call constructor on uninitialized memory in C++
我有一些遗留的 C++(10 年以上),我试图在有 buffer/allocator 的地方编译,它用于为新对象获取一些内存。然后调用一个函数 std::_Construct
,我假设它用于调用对象的构造函数(因为分配器只有 returns a void*
)。但我怀疑它只是旧版本 Visual Studio 的一个特性(我找不到 VS2015 之前的任何东西),所以我想知道:如何在一块未初始化的内存上调用构造函数已转换为我正在尝试构建的 class?
这是我要实现的一些伪代码:
BufferManagementClass mBuffMan; // "allocator"
class A { ... };
A* initObject() {
A* pA = static_cast<A*>(mBuffMan.GetBuffer(sizeof(A))); // GetBuffer returns void*, so I cast it.
if (pA == NULL)
return NULL;
/*
How do I call the constructor of the memory pA points to here?
I assume that is needed before I can call any methods in pA?
*/
pA->someFunc();
pA->someOtherFunc();
return pA;
}
顺便把项目转成C++14(因为这是VS2019支持的最早的标准版本)
标准库中没有std::_Construct
。下划线 + 大写前缀表示这是标准库的语言扩展或实现细节。由于在版本变更中消失了,估计是后者
在已可用 24 年以上的未初始化存储中创建对象的标准方法是使用 placement-new 语法:
void* memory = mBuffMan.GetBuffer(sizeof(A))
A* aP = new(memory) A(/*constructor arguments*/);
自 C++11 起,替代方案是 std::allocator_traits::construct
。这具有自 C++20 以来成为 constexpr 的优势。当您使用分配器时,这种方法很常见,这在分配和对象创建分离时非常典型:
using ExampleAlloc = std::allocator<A>;
using AT = std::allocator_traits<ExampleAlloc>;
ExampleAlloc alloc{};
A* aP = AT.allocate(alloc, 1);
AT.construct(alloc, memory, /*constructor arguments*/);
在 C++11 之前,使用 std::allocator::construct
也是可能的,但在 C++17 中已弃用,取而代之的是使用 std::allocator_traits
,并在 C++20 中删除。
另一种选择,当您处理将多个对象创建到内存中时,是使用 std::uninitialized_copy
、std::uninitialized_fill
、std::uninitialized_move
(C++17)、std::uninitialized_default_construct
(C++17), std::uninitialized_value_construct
(C++17):
extern A value;
A* aP = AT.allocate(alloc, count);
std::uninitialized_fill_n(aP, count, value);
最后,C++20 添加了另一种选择,std::construct_at
。
C++20 解决方案也是std::construct_at
. But you can use the traditional placement new
。
我有一些遗留的 C++(10 年以上),我试图在有 buffer/allocator 的地方编译,它用于为新对象获取一些内存。然后调用一个函数 std::_Construct
,我假设它用于调用对象的构造函数(因为分配器只有 returns a void*
)。但我怀疑它只是旧版本 Visual Studio 的一个特性(我找不到 VS2015 之前的任何东西),所以我想知道:如何在一块未初始化的内存上调用构造函数已转换为我正在尝试构建的 class?
这是我要实现的一些伪代码:
BufferManagementClass mBuffMan; // "allocator"
class A { ... };
A* initObject() {
A* pA = static_cast<A*>(mBuffMan.GetBuffer(sizeof(A))); // GetBuffer returns void*, so I cast it.
if (pA == NULL)
return NULL;
/*
How do I call the constructor of the memory pA points to here?
I assume that is needed before I can call any methods in pA?
*/
pA->someFunc();
pA->someOtherFunc();
return pA;
}
顺便把项目转成C++14(因为这是VS2019支持的最早的标准版本)
标准库中没有std::_Construct
。下划线 + 大写前缀表示这是标准库的语言扩展或实现细节。由于在版本变更中消失了,估计是后者
在已可用 24 年以上的未初始化存储中创建对象的标准方法是使用 placement-new 语法:
void* memory = mBuffMan.GetBuffer(sizeof(A))
A* aP = new(memory) A(/*constructor arguments*/);
自 C++11 起,替代方案是 std::allocator_traits::construct
。这具有自 C++20 以来成为 constexpr 的优势。当您使用分配器时,这种方法很常见,这在分配和对象创建分离时非常典型:
using ExampleAlloc = std::allocator<A>;
using AT = std::allocator_traits<ExampleAlloc>;
ExampleAlloc alloc{};
A* aP = AT.allocate(alloc, 1);
AT.construct(alloc, memory, /*constructor arguments*/);
在 C++11 之前,使用 std::allocator::construct
也是可能的,但在 C++17 中已弃用,取而代之的是使用 std::allocator_traits
,并在 C++20 中删除。
另一种选择,当您处理将多个对象创建到内存中时,是使用 std::uninitialized_copy
、std::uninitialized_fill
、std::uninitialized_move
(C++17)、std::uninitialized_default_construct
(C++17), std::uninitialized_value_construct
(C++17):
extern A value;
A* aP = AT.allocate(alloc, count);
std::uninitialized_fill_n(aP, count, value);
最后,C++20 添加了另一种选择,std::construct_at
。
C++20 解决方案也是std::construct_at
. But you can use the traditional placement new
。