将新放置到缓冲区后,缓冲区和实例是否具有相同的 void* 地址?
After placement-new into buffer, do buffer and instance have same void* address?
请参阅下面的代码:
unsigned char* p = new unsigned char[x];
CLASS* t = new (p) CLASS;
assert((void*)t == (void*)p);
我可以假设(void*)t == (void*)p
吗?
是的,你可以。我相信这是有几项规定的保证。
-
[exr.new]/10 - 强调我的
新表达式将请求的空间量传递给 分配函数作为类型std::size_t的第一个参数。 参数应不小于正在创建的对象的大小; 它可能大于正在创建的对象的大小,仅当 对象是一个数组。对于字符和无符号字符数组, 新表达式的结果与地址之间的差异 分配函数返回的整数倍应是 最严格的基本对齐要求([基本对齐]) 大小不大于数组大小的对象类型 创建。[ 注意:因为假设分配函数返回 指向与任何对象适当对齐的存储的指针 具有基本对齐的类型,此约束对数组分配 开销允许将字符数组分配给 稍后将放置哪些其他类型的对象。 — 尾注 ]
对我来说,这读起来就像新表达式必须在分配函数返回的确切地址处创建一个对象(假设它不是数组类型)。由于您使用的是内置的放置 new,这将带我们了解以下内容
-
[新建.删除.放置]
这些功能是保留的,C++程序可能无法定义功能 替换标准C++库中的版本 ([约束])。([basic.stc.dynamic])的规定不适用 到这些保留的放置形式为运算符新建和运算符删除。
void* operator new(std::size_t size, void* ptr) noexcept;
返回:PTR。
备注:故意不执行其他操作。
这保证了传递给表达式的地址是您分配的字符数组对象的确切地址。这是因为转换为
void*
不会更改源地址。
我认为保证地址相同就足够了,即使指针通常不可互换。因此,根据 [expr.eq]/1(感谢 @T.C.):
相同类型的两个指针比较相等当且仅当它们是 两者都为 null,都指向同一函数,或者都表示相同的函数 地址([基本化合物])。
比较必须产生 true,同样是因为地址相同。
我可以假设
(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; }
};
如果您希望此新表达式调用标准非分配放置新运算符,则代码需要
- 包括标头
<new>
。 - 确保传递一个
void*
参数。 - 在它前面加上范围解析运算符
::
以绕过CLASS::operator new
,如果有的话。
例如:
#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)...);
}
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- C++字符*缓冲区的大小
- 在c++类上调用void函数
- 为什么野牛仍在使用"int yylex(void)",却找不到"int yylex(YYS
- 为什么msgrcv()将垃圾字符馈送到缓冲区
- 在派生函数中指定void*参数
- C++为什么尽管我调用了void函数,它却不起作用
- 如何从void函数输出字符串
- 我应该使用什么来代替void作为变体中的替代类型之一
- 奇怪的结构&GCC&clang(void*返回类型)
- Arduino:for/while/if在void setup()或void loop()之前?——错误:之前需要不合格
- 使用动态分配的数组会导致代码分析发出虚假的C6386缓冲区溢出警告
- ostream过载时的缓冲区冲洗
- 为什么这个函数将"const char*"转换为"void* const"而不是"const void*"
- 如何从平面缓冲区中反序列化联合结构的 void* 值的大小
- 将新放置到缓冲区后,缓冲区和实例是否具有相同的 void* 地址?
- 将缓冲区(void*)写入 rocksdb
- 使用*void作为static_cast的缓冲区
- c++ Builder读取TMemoryStream缓冲区到void指针
- 将无符号char*缓冲区强制转换为可接受参数的可调用void指针