【问题标题】:In what cases do we need to know if a class is trivial?在什么情况下我们需要知道一个类是否微不足道?
【发布时间】:2013-02-05 18:00:50
【问题描述】:

std::is_trival<T>::value 可以确定类 T 是否微不足道。但是,我想不出需要这些信息的场景。

有例子吗?

我的一些想法:

假设 T 类是微不足道的,是否意味着 T 可以像这样被memcpy 安全复制:

T t1, t2;
memcpy(&t1, &t2, sizeof(T));

?

【问题讨论】:

标签: c++ class c++11 typetraits


【解决方案1】:

如果一个类型是平凡的,例如,它可以用memcpy 复制。这是用作std::atomic 模板参数的用户定义类型的要求。也就是说,对于用户定义的类型Tatomic<T> 被允许(并且,对于更大的类型,需要)实现从T 类型的对象到atomic<T> 类型的对象的赋值memcpy .同样,在需要时使用 memcmp 进行相等性测试。

使用这些 C 函数而不是 C++ 运算符的原因是原子操作不会对用户代码进行任何调用。这样做可能会导致看似无辜的代码出现神秘的死锁。

【讨论】:

  • 另一件事是,普通类型不需要调用其析构函数,这可能会提高std::vector<trivial> 的效率。所以这不仅是安全,而且是简单的效率。
  • @Xeo - 是的,但我认为这并不能回答所提出的问题,即“我什么时候需要知道这个”?嗯,想想看,我的也没有回答这个问题:如果你定义一个原子类型,你知道你的类型是微不足道的,不需要类型特征来告诉你。
  • 我认为它很好地回答了这个问题——“我什么时候需要知道这个?” - “当你想编写尽可能高性能的代码时”和“当特殊要求使非平凡类型成为不可行时”。您可以说它(就像 C++ 的许多部分一样)只对库编写者真正有用,但是嗯...
  • 只有在可以接受虚假不等式的情况下才允许将平凡类型与std::memcmp() 进行比较。它是由于非规范表示而发生的,例如查看浮点和填充。
【解决方案2】:

真的,普通类型对 /anything/ 很有用,它只需要一个字符指针和一个长度。 Pete Becker 的回答描述了重要的情况,但这里有些愚蠢:您可以使用 std::ostream::write 序列化一个普通类型,然后使用 std::istream::read 将其读回。

template<typename T>
std::enable_if<std::is_trivial<T>, void> 
bin_write(std::ostream& out, const T& data) {
  out.write(reinterpret_cast<const char*>(&data), sizeof(T));
}

template<typename T>
std::enable_if<std::is_trivial<T>::value, T> 
bin_read(std::istream& in) {
  using T_in = std::remove_cv_t<T>; //even if T is const, the buffer can't be
  T_ buffer;
  in.read(reinterpret_cast<char*>(&buffer), sizeof(T_));
  return buffer;
}

显然你不能在原始指针(或原始指针包装器,例如std::experimental::observer_ptr)上使用它。这会忽略字节顺序,因此您可能不想将此数据发送到其他计算机上的其他应用程序。但是,如果您想编写模拟重启文件,或者如果您需要在 GCC 编译的 C++ 和 GCC 编译的 Fortran 之间传输数据,它会很有用。

【讨论】:

  • 澄清一下:Fortran 有点老,并且没有与 C 或 C++ 几乎相同的标准化水平,因此在 Fortran 标准库或其内置库中对序列化和反序列化的保证较少运营商。结果是 C++ 中的特性,如 std::is_trivial,以及围绕它的标准中的所有保证,绝对是神圣的。
猜你喜欢
  • 2011-02-10
  • 2022-01-18
  • 2018-10-29
  • 1970-01-01
  • 1970-01-01
  • 2011-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多