c++11 中的类型何时允许内存
When is a type in c++11 allowed to be memcpyed?
我的问题如下:
如果我想复制一个类类型,memcpy可以非常快地完成。在某些情况下,这是允许的。
我们有一些类型特征:
- is_standard_layout。
- is_trivially_copyable。
我想知道的是类型何时"按位可复制"的确切要求。
我的结论是,如果is_trivally_copyable
和is_standard_layout
特征都为真,则类型是按位可复制的:
- 这正是我需要按位复制的吗?
- 是不是过分约束了?
- 是否约束不足?
PS:当然,memcpy的结果一定是正确的。我知道我在任何情况下都可以做模思妙想,但不正确。
为 true 时,可以使用 memcpy
复制 T 类型的对象is_trivially_copyable<T>::value
。类型不需要是标准布局类型。"微不足道的可复制"的定义本质上是这样做是安全的。
可以使用memcpy
安全复制但不是标准布局的类示例:
struct T {
int i;
private:
int j;
};
由于此类对不同的非静态数据成员使用不同的访问控制,因此它不是标准布局,但它仍然是可复制的。
如果is_trivally_copyable<T>::value
(或在 C++14 is_trivially_copyable<T>()
中,或在 C++17 is_trivially_copyable_v<T>
中)不为零,则该类型可使用 memcpy
进行复制。
根据C++标准,可复制的类型意味着:
构成对象的基础字节可以复制到数组中字符或无符号字符。如果将字符数组或无符号字符的内容复制回对象,则对象随后应保持其原始值。
但是,重要的是要意识到指针也是微不足道的可复制类型。每当要复制的数据结构中有指针时,您都必须在大脑上确保复制它们是正确的。
仅依靠可复制的对象可能造成危害的示例:
- 一种树结构实现,其中数据放置在连续的内存区域中,但节点存储子节点的绝对地址
- 为了多线程性能(以减少缓存崩溃)创建某些数据的多个实例,内部拥有指针,指向任何地方
- 你有一个没有指针的平面对象,但内部有一个嵌入的第三方结构。将来的某个时候,第三方结构包括一个不应存在两次或更多次的指针。
因此,每当进行忆术复制时,请记住检查在特定情况下是否可以复制指针,以及是否可以。
意识到is_trivially_copyable
只是编译器术语中的"语法检查",而不是"语义测试"。
从 http://en.cppreference.com/w/cpp/types/is_trivially_copyable:
简单可复制类型的对象是唯一可以使用
std::memcpy
安全地复制或使用std::ofstream::write()/std::ifstream::read()
序列化到二进制文件/从二进制文件序列化到/从二进制文件序列化C++对象。通常,简单可复制类型是可以将基础字节复制到 char 或无符号 char 数组并复制到相同类型的新对象中的任何类型,并且生成的对象将具有与原始对象相同的值。
具有普通复制构造函数、简单复制赋值运算符和可以使用 memcpy
或 memmove
复制简单的析构函数
类T
的特殊成员函数的要求是微不足道
复制构造函数 (cc) 和复制赋值运算符 (ca)
- 不是用户提供的(意味着,它是隐式定义的或默认的),如果它是默认的,它的签名与隐式定义的签名相同
-
T
没有虚拟成员函数 -
T
没有虚拟基类 - 为每个
T
的直接碱基选择的cc/ca是微不足道的 - 为
T
的每个非静态类类型(或类类型数组)成员选择的 cc/ca 是微不足道的 -
T
没有可变限定类型的非静态数据成员(自 C++14 起)
析 构 函数
- 不是用户提供的(意味着,它是隐式定义的或默认的)
- 不是虚拟的(即基类析构函数不是虚拟的)
- 所有直接基类都有简单的析构函数
- 类类型(或类类型的数组)的所有非静态数据成员都有简单的析构函数
仅将函数声明为 = default
并不能使其变得微不足道(只有在以下情况下才会变得微不足道该类还支持相应函数的所有其他条件是微不足道的)但是在用户代码中显式编写函数确实可以防止它变得微不足道。此外,所有与 C 语言兼容的数据类型(POD 类型)都是可复制的。
来源 : C++ 操作和 cppreference.com 中的并发
我的理解是
- 对象应具有默认构造函数/析构函数。
- 默认复制和移动操作。
- 没有静态和虚拟函数有多个
- 非静态数据成员的访问说明符可防止重要的
- 布局优化具有非静态成员或不是标准布局。
您可以使用标准函数 is_pod::value 来测试给定的类型是否为 pod(纯旧数据)
参考:C++编程语言第4版
- 将字符串存储在c++中的稳定内存中
- C++ 指针的内存地址和指向数组的内存地址如何相同?
- Win32编译器选项和内存分配
- 当vector是tje全局变量时,c++中vector的内存管理
- 带内存和隔离功能的SQLite
- 是否可以通过C++扩展强制多个python进程共享同一内存
- 迭代时从向量和内存中删除对象
- 在C++中打印指向不同基元数据类型的指针的内存地址
- 这个指针和内存代码打印是什么?我不知道是打印垃圾还是如何打印我需要的值
- 多个文件的内存分配错误"在抛出 'std :: bad_alloc' what (): std :: bad_alloc 的实例后终止调用" [C++]
- 为什么示例代码访问IUnknown中已删除的内存
- 如何在C++类内存结构中创建"spacer"?
- 从构造函数抛出异常时如何克服内存泄漏
- std::函数 创建临时内存时内存访问错误
- 在插入C STL地图之前,我需要使用新的内存分配内存
- 即使仍有足够的内存,内存分配也会失败
- 内存集内存溢出
- 内存映射内存是否可能
- 写入大于系统内存的内存映射区域
- 内存和内存管理与pcap