请参阅以下代码:
unsigned char* p = new unsigned char[x];
CLASS* t = new (p) CLASS;
assert((void*)t == (void*)p);
我可以假设(void*)t == (void*)p
吗?
答案 0 :(得分:12)
是的,你可以。我相信它有几个条款的保证。
[expr.new]/10 - 强调我的
new-expression传递请求的空间量 allocation函数作为std :: size_t类型的第一个参数。的即 参数应不小于正在创建的对象的大小; 它可能大于正在创建的对象的大小 对象是一个数组。对于char和unsigned char的数组, new-expression的结果与地址之间的差异 由分配函数返回的应是整数倍 任何最严格的基本对齐要求([basic.align]) 对象类型,其大小不大于数组的大小 创建。 [注意:因为假定分配函数返回 存储指针,适用于任何对象的对齐 具有基本对齐的类型,这种对数组分配的约束 开销允许分配字符数组的常用习惯用法 稍后将放置其他类型的对象。 - 结束说明]
对我而言,新表达式必须在分配函数返回的确切地址处创建一个对象(假设它不是数组类型)。由于您使用的是内置展示位置新功能,因此我们将使用以下内容
这些函数是保留的,C ++程序可能无法定义函数 取代标准C ++库中的版本 ([约束])。 ([basic.stc.dynamic])的规定不适用 这些保留的运营商新格式和运营商删除格式。
void* operator new(std::size_t size, void* ptr) noexcept;
返回:ptr。
备注:故意不执行任何其他操作。
这保证传递给表达式的地址是您分配的字符数组对象的确切地址。这是因为转换为void*
不会更改源地址。
我认为它足以承诺地址是相同的,即使指针通常不可互换。所以根据[expr.eq]/1(感谢@ T.C。):
同一类型的两个指针比较相等,当且仅当它们相同时 两者都为null,都指向相同的函数,或都表示相同 地址([basic.compound])。
比较必须产生真,再次因为地址相同。
答案 1 :(得分:8)
我可以假设
(void*)t == (void*)p
吗?
不一定。
例如,如果类的作者重载CLASS::operator new(size_t, unsigned char*)
,那么该运算符可以返回除第二个参数之外的任何内容,例如:
struct CLASS
{
static void* operator new(size_t, unsigned char* p) { return p + 1; }
};
如果您希望此新表达式调用the standard non-allocating placement new operator,则代码需要
<new>
。void*
参数。::
对其进行前缀,以绕过CLASS::operator new
,如果有的话。E.g:
#include <new>
#include <cassert>
unsigned char p[sizeof(CLASS)];
CLASS* t = ::new (static_cast<void*>(p)) CLASS;
assert(t == static_cast<void*>(p));
在这种情况下t == static_cast<void*>(p)
确实。
事实上,这就是GNU C ++标准库的作用:
template<typename _T1, typename... _Args>
inline void _Construct(_T1* __p, _Args&&... __args) {
::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...);
}