2

我的问题是关于 Scott Meyer 的书“更有效的 C++ 35 种新方法......”中的代码快照

代码(参数名称已更改)

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);
}

我不熟悉这种语法。甚至运算符 new [] 和 new (&myArray[i]) ... 是否有任何资源可以阅读有关该语法的详细信息,它们是如何工作的。

4

4 回答 4

2
void * memory = operator new[] (10*sizeOf(MyClass));

在这里,您分配 size10*sizeOf(MyClass)字节的内存。这是未初始化的原始内存。此内存中没有构造 C++ 对象。

new (&myArray[i]) MyClass(params);

在这里,您使用placement-new在 指向的给定内存中构造一个对象&myArray[i]

Placement-new 的典型语法是这样的:

X * x = new (pAllocatedMem) X(a,b,c);

这意味着,您构造一个将 , 传递给构造函数的类型的X对象。该对象在 指向的内存中构造。abcpAllocatedMem

另请注意,您删除了使用placement-new构造的此类对象,例如:

x->~X(); //delete the constructed object. DONT USE : delete x;

也就是说,您不必delete x删除此类对象。

于 2012-11-04T12:30:15.793 回答
2

维基百科将回答您的问题。

第一个new是分配原始内存。

http://en.wikipedia.org/wiki/New_(C%2B%2B)#void.2A_operator_new.28size_t_size.29

仅分配内存的 C++ 语言结构称为 void* operator new(size_t size)。它在分配阶段被 new 使用。它可以被每个类覆盖以定义特定于类的内存分配器。


第二个new称为安置新。

http://en.wikipedia.org/wiki/Placement_new

使用额外的 void * 参数的 operator new 和 operator delete 的放置重载用于默认放置,也称为指针放置。

于 2012-11-04T12:30:22.390 回答
2

要理解这一点,您首先需要了解简单明了的new工作原理。表达式的常用语法new类似于new T. 使用new表达式时,会发生以下情况:

  1. 首先,它调用分配函数来获取对象的存储空间。分配函数只需返回一个指针,该指针指向某个已分配的存储空间,该存储空间足够大以适合所请求的对象。它仅此而已。它不会初始化对象。

  2. 接下来,在分配的空间中初始化对象。

  3. 返回指向已分配空间(以及现在已初始化的对象)的指针。

在 的情况下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]现在将指向第一个MyClassmyArray[1]第二个。

现在我们遍历该数组,调用placement new,并使用每个未初始化MyClass大小的已分配存储位的地址。例如,在第一次迭代中,这将调用分配函数operator new(sizeof(MyClass), &myArray[0]),正如我们之前看到的,它什么都不做,只是返回你给它的指针。新表达式将通过MyClass在这个空间中初始化一个对象并返回指向它的指针来完成。

所以总而言之,代码分配了一些存储空间来容纳 10 个MyClass对象(但不初始化它们),然后循环遍历MyClass该存储空间中的每个 -size 空间,在每个对象中初始化一个对象。

这演示了如何在已经预分配的存储中初始化对象。您可以对新初始化的对象反复重用相同的存储。

于 2012-11-04T13:01:54.817 回答
1
new (&myArray[i]) MyClass(params);

放置new运算符。它允许您在预分配的内存位置创建对象。

18.4.1.3 安置表格

void* operator new(std::size_t size, void* ptr) throw();

返回:ptr。
3 注释:故意不执行其他动作。
4 [示例:这对于在已知地址构造对象很有用:

void* place = operator new(sizeof(Something));

Something* p = new (place) Something();
—end example]

void* operator new[](std::size_t size, void* ptr) throw();

5 Returns: ptr.
6 Notes: Intentionally performs no other action.
于 2012-11-04T12:29:59.847 回答