要理解这一点,您首先需要了解简单明了的new
工作原理。表达式的常用语法new
类似于new T
. 使用new
表达式时,会发生以下情况:
首先,它调用分配函数来获取对象的存储空间。分配函数只需返回一个指针,该指针指向某个已分配的存储空间,该存储空间足够大以适合所请求的对象。它仅此而已。它不会初始化对象。
接下来,在分配的空间中初始化对象。
返回指向已分配空间(以及现在已初始化的对象)的指针。
在 的情况下new T
,分配函数被命名为operator new
。分配数组时,如new T[5]
,分配函数名为operator new[]
。这些函数的默认定义在全局命名空间中提供。它们每个都采用一个类型的参数,std::size_t
即所需的字节数。因此,当您这样做时new T
,相应的调用是 to ,operator new(sizeof(T))
而 for被调用。new T[5]
operator new[](sizeof(T)*5)
但是,可以将更多参数传递给分配函数。这称为放置新语法。要传递更多参数,您可以使用如下语法:new (some, arguments, 3) T
,它将调用operator new(sizeof(T), some, arguments, 3)
. 参数列表放在new
和类型之间的括号中。
除了operator new(std::size_t)
由实现提供的 simple 及其对应的数组之外,还有一些默认定义采用额外的 type 参数void*
。也就是说,它们采用指向对象的指针。这些函数实际上并不分配任何空间,而只是返回您给它们的指针。因此,当您这样做时new (some_pointer) T
,它首先调用operator new(sizeof(T), some_pointer)
whichsome_pointer
再次返回,然后初始化该空间中的对象。这为您提供了一种在某些已分配空间中初始化对象的方法。
所以现在我们有了这四个预定义的分配函数(事实上,还有一些其他的,你也可以自由定义自己的):
// Normal allocation functions that allocate space of the given size
operator new(std::size_t)
operator new[](std::size_t)
// Placement allocation functions that just return the pointer they're given
operator new(std::size_t, void*)
operator new[](std::size_t, void*)
因此,让我们看一下您提供的代码片段:
void * memory = operator new[] (10*sizeOf(MyClass));
MyClass * myArray = static_cast<MyClass*>(memory);
for(int i= 0; i<10; i++)
{
new (&myArray[i]) MyClass(params);
}
在第一行,我们operator new[]
直接调用分配一些存储空间。多少存储空间?好吧,足以容纳 10 个类型的对象MyClass
。此函数返回一个指向该分配存储的指针,并将其存储在memory
.
在此之后,void*
被强制转换为 aMyClass*
以允许您以 size 的块索引分配的存储sizeof(MyClass)
,即myArray[0]
现在将指向第一个MyClass
和myArray[1]
第二个。
现在我们遍历该数组,调用placement new,并使用每个未初始化MyClass
大小的已分配存储位的地址。例如,在第一次迭代中,这将调用分配函数operator new(sizeof(MyClass), &myArray[0])
,正如我们之前看到的,它什么都不做,只是返回你给它的指针。新表达式将通过MyClass
在这个空间中初始化一个对象并返回指向它的指针来完成。
所以总而言之,代码分配了一些存储空间来容纳 10 个MyClass
对象(但不初始化它们),然后循环遍历MyClass
该存储空间中的每个 -size 空间,在每个对象中初始化一个对象。
这演示了如何在已经预分配的存储中初始化对象。您可以对新初始化的对象反复重用相同的存储。