我的问题是关于来自Scott Meyer的书“更有效的C ++ 35新方法......”的代码snanpshot。
代码(参数名称已更改)
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(&amp; myArray [i])...是否有任何资源我可以详细了解该语法,它们是如何工作的。
答案 0 :(得分:2)
void * memory = operator new[] (10*sizeOf(MyClass));
这里分配大小为10*sizeOf(MyClass)
个字节的内存。这是原始未初始化的内存。在这个内存中没有构造C ++对象。
new (&myArray[i]) MyClass(params);
在这里,您使用 placement-new 在&myArray[i]
指向的给定内存中构造一个对象。
placement-new的典型语法是:
X * x = new (pAllocatedMem) X(a,b,c);
这意味着,您构造了一个X
类型的对象,将a
,b
,c
传递给构造函数。该对象是在pAllocatedMem
指向的内存中构造的。
另请注意,您删除了使用placement-new构建的对象,如:
x->~X(); //delete the constructed object. DONT USE : delete x;
也就是说,您没有delete x
删除此类对象。
答案 1 :(得分: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的放置重载用于默认放置,也称为指针放置。
答案 2 :(得分:2)
要理解这一点,首先需要了解简单new
的工作原理。 new
表达式的通常语法类似于new T
。使用new
表达式时,会发生以下情况:
首先,它调用分配函数来获取对象的存储空间。分配函数只需返回一个指向某个已分配存储的指针,该指针足够大以适合所请求的对象。它只不过是这个。它不会初始化对象。
接下来,在分配的空间中初始化对象。
返回指向已分配空间(现在已初始化的对象)的指针。
在new T
的情况下,分配函数名为operator new
。分配数组(例如new T[5]
)时,分配函数名为operator new[]
。全局命名空间中提供了这些函数的缺省定义。它们各自采用类型std::size_t
的单个参数,这是所需的字节数。因此,当您执行new T
时,相应的调用将发送到operator new(sizeof(T))
,而new T[5]
则调用operator new[](sizeof(T)*5)
。
但是,可以将更多参数传递给分配函数。这称为 placement new 语法。要传递更多参数,请使用如下语法:new (some, arguments, 3) T
,它将调用operator new(sizeof(T), some, arguments, 3)
。参数列表位于new
和类型之间的括号中。
除了由实现提供的简单operator new(std::size_t)
及其数组副本之外,还有一些默认定义采用类型void*
的额外参数。也就是说,它们采用指向对象的指针。这些函数实际上并没有分配任何空间,只是返回你给它们的指针。因此,当您执行new (some_pointer) T
时,它首先调用operator new(sizeof(T), some_pointer)
,然后再次返回some_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*
将转换为MyClass*
,以允许您将大小为sizeof(MyClass)
的块中的已分配存储编入索引,即myArray[0]
现在将指向第一个MyClass
和myArray[1]
到第二个。
现在我们循环遍历该数组,使用每个未初始化MyClass
大小的已分配存储空间的地址调用 placement new 。例如,在第一次迭代中,这将调用分配函数operator new(sizeof(MyClass), &myArray[0])
,正如我们之前看到的那样,它只会返回你给它的指针。新表达式将通过初始化此空间中的MyClass
对象并将指针返回给它来完成。
总而言之,代码分配一些存储空间以适应10 MyClass
个对象(但不初始化它们),然后循环遍历该存储中的每个MyClass
大小的空间,初始化一个对象他们每个人。
这演示了如何在已预先分配的存储中初始化对象。您可以使用新初始化的对象重复使用相同的存储。
答案 3 :(得分: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.