常量正确清洗 Pod(普通旧数据)
const correct laundering of pods (plain old data)
为了绕过混叠和字节重新解释规则,我有一个名为T* landry_pod<T>(void*)
的实用程序函数,它假装复制字节并创建新对象。 它在优化下编译为无,因为每个编译器都可以看到我将字节放回了它们开始的位置。
template<class T>
T* laundry_pod( void* data ){
static_assert( std::is_pod<T>{} ); // or more verbose replacement as pod is gone
char tmp[sizeof(T)];
std::memcpy( tmp, data, sizeof(T) );
T* r = ::new(data) T;
std::memcpy( data, tmp, sizeof(T) );
return r;
}
这可确保数据点所在的sizeof(T)
位数据点相同,但返回指向该T
类型的对象的指针。 这是一种符合标准的方法,当data
只指向位而不是实际对象时,可以执行T* r = (T*)data;
。 它在运行时优化到 0 条指令。
遗憾的是,虽然它在运行时什么都不做,但在逻辑上不能在const
缓冲区上使用。
这是我尝试修改它以使用const
输入和输出:
template<class T, std::enable_if_t<std::is_const<T>{}, bool> = true, class In>
T* laundry_pod( const In* data ){
static_assert( sizeof(In)==1 ); // really, In should be byte or char or similar
static_assert( std::is_pod<T>{} ); // or more verbose replacement as pod is gone
std::byte tmp[sizeof(T)];
std::memcpy( tmp, data, sizeof(T) ); // copy bytes out
for(std::size_t i =0; i<sizeof(T); ++i)
data[i].~In(); // destroy const objects there // is this redundant?
auto* r = ::new( (void*)data ) std::remove_const_t<T>; // cast away const on data (!)
std::memcpy( r, tmp, sizeof(T) ); // copy same bytes back
return r;
}
在这里,我销毁 const 对象(井字节),然后在它们的位置构造一个新对象。
以上应该优化为 0 条指令(试试吧),但是当我创建r
时我不得不丢弃 const .
如果data
指向常量字符或字节的连续缓冲区,那么销毁这些对象是否足以允许我重用存储并保持在定义的行为土地上? 或者简单地创建新对象就足够了? 还是我注定要失败?
假设没有人事先使用旧的In
指针来访问原始字节。
您问题的核心是重用const
对象的存储的定义行为?答案是否定的,根据basic.life#9:
在具有静态、线程或自动存储持续时间的 const 对象所占用的存储位置创建新对象,或者在此类 const 对象在其生存期结束之前曾经占用的存储位置创建新对象会导致未定义的行为。
[示例:
struct B { B(); ~B(); }; const B b; void h() { b.~B(); new (const_cast<B*>(&b)) const B; // undefined behavior }
—结束示例]
表面上,这是因为数据可能放在只读内存中。因此,尝试修改const
数据是无操作也就不足为奇了。
为了补充其他答案,原始函数实际上根本不是标识 - 您仍然会导致原始缓冲区的读取和写入,这可能与并发使用方案中的普通读取具有不同的语义。特别是,在同一缓冲区上同时调用laundry_pod
的多个线程是 UB。
- 防止主数据类型C++的隐式转换
- 用于访问容器<T>数据成员的正确 API
- 嵌套在类中时无法设置成员数据
- 使用流处理接收到的数据
- 静态数据成员的问题-修复链接错误会导致编译器错误
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 在cuda线程之间共享大量常量数据
- C++将文本文件中的数据读取到结构数组中
- 如何在C++中序列化结构数据
- 在C++中打印指向不同基元数据类型的指针的内存地址
- 通过套接字[TCP]传输数据 如何在C / C ++中打包多个整数并使用send() recv()传输数据
- 在c代码之间共享数据的最佳方式
- 链表,反向函数,数据结构
- 数据成员SFINAE的C++17测试:gcc vs clang
- C++浮点数据类型和字符串数据类型无法子到模板函数中
- 如何对点云数据进行排序
- 从矢量<无符号字符>转换为字符* 包括垃圾数据
- 尝试通过OCI例程从Oracle获取blob数据,但出现错误:ORA-01008:并非所有变量都绑定
- Cuda C++:设备上的Malloc类,并用来自主机的数据填充它
- 常量正确清洗 Pod(普通旧数据)