C++ Sytanx 关于类数组和新运算符的使用
C++ Sytanx about Array of Class and usage of new operator
我的问题是关于斯科特·迈耶(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 [] 和新的 (&myArray[i]) ...是否有任何资源可以阅读有关该语法的详细信息,它们是如何工作的。
要理解这一点,您首先需要了解简单明了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)
被调用。
但是,可以将更多参数传递给分配函数。这称为放置新语法。要传递更多参数,请使用如下语法: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
大小位的地址调用放置 new。例如,在第一次迭代中,这将调用分配函数operator new(sizeof(MyClass), &myArray[0])
正如我们之前看到的,它除了返回你给它的指针外什么都不做。新表达式将通过初始化此空间中的MyClass
对象并返回指向该对象的指针来完成。
因此,总而言之,代码分配一些存储以适应 10 个MyClass
对象(但不初始化它们),然后循环遍历该存储中的每个MyClass
大小的空间,初始化每个对象中的对象。
这演示了如何在已预分配的存储中初始化对象。您可以对新初始化的对象一遍又一遍地重复使用相同的存储。
维基百科将回答您的问题。
第一个new
用于分配原始内存。
http://en.wikipedia.org/wiki/New_(C%2B%2B)#void.2A_operator_new.28size_t_size.29
仅分配内存的C++语言结构称为 void* 运算符 new(size_t 大小)。它由新人在分配阶段使用。可以按类重写它以定义特定于类的内存分配器。
第二个new
称为放置新。
http://en.wikipedia.org/wiki/Placement_new
使用附加 void * 参数的运算符 new 和运算符删除的放置重载用于默认放置,也称为指针放置。
void * memory = operator new[] (10*sizeOf(MyClass));
在这里,您可以分配大小为10*sizeOf(MyClass)
字节的内存。这是原始未初始化的内存。此内存中没有构造C++对象。
new (&myArray[i]) MyClass(params);
在这里,您使用placement-new在&myArray[i]
指向的给定内存中构造一个对象。
放置-new 的典型语法是这样的:
X * x = new (pAllocatedMem) X(a,b,c);
这意味着,你构造一个类型为X
的对象,将a
、b
、c
传递给构造函数。该对象是在pAllocatedMem
指向的内存中构造的。
另请注意,您删除使用放置新构造的此类对象,例如:
x->~X(); //delete the constructed object. DONT USE : delete x;
也就是说,您无需执行delete x
即可删除此类对象。
new (&myArray[i]) MyClass(params);
是放置new
运算符。它允许您在预先分配的内存位置创建对象。
18.4.1.3 放置表格
void* 运算符 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.
- 为什么比较运算符如此快速
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- 使用C++中的模板和运算符重载执行矩阵运算
- 为什么这个运算符<重载函数对 STL 算法不可见?
- 增量运算符与后缀混淆
- 一个关于在C++中重载布尔运算符的问题
- 运算符C++ "delete []"仅删除 2 个前值
- 模板类无法识别友元运算符
- 我可以使用条件运算符初始化C风格的字符串文字吗
- 关闭||运算符优化
- 通过继承类使用来自不同命名空间的运算符
- C++Cast运算符过载
- 如何使用AngelScript注册SFML Vector2运算符
- 重载元组索引运算符-C++
- 如何使用重载的相等(==)运算符向测试用例添加描述
- 为什么Mat类的两个对象可以在不重载运算符+的情况下添加
- 多个If语句与使用逻辑运算符计算条件的单个语句的比较
- 布尔比较运算符是如何在C++中工作的
- 重载运算符new[]的行为取决于析构函数
- C++ Sytanx 关于类数组和新运算符的使用