C ++保证和POD类数据的名称,具有memcpy功能

时间:2011-03-25 09:45:54

标签: c++ c++11

在另一个question中,我错误地使用术语POD来引用实际上不是POD类型的数据类型(由于具有构造函数)。现在,我已经查看了标准,找不到我想要的正确名称。我实际上也无法确保实际允许复制。

我所说的数据类型是一个POD,但可能包含函数,包括构造函数,但与等效的POD类型相比,不应改变其对齐或大小特征。

在标准的第3.9节中,它指出POD数据可以用memcpy复制到另一个对象,或者复制到字符数据和后面。没有这种非POD数据的保证。

但是,对象的对象表示在同一节中定义。它被定义为可以相信任何两个相同类型的对象都可以通过memcpy安全地复制。

所以我的问题是:

  1. 具有memcpy的副本实际上是否确保对这些对象安全?
  2. 如果是,那么为什么有关于memcpy和POD的特别说明?
  3. 这种类型的数据是否有memcpy安全的名称?

  4. 我的意思是对象类型的简单示例:

    struct ex_struct
    {
      int a,b,c,d;
      ex_struct() : a(123) { }
    }
    

    阅读C ++ 0x草案,我的结构似乎是一个平易可复制的类(9.1)。我认为这意味着memcpy是安全的。

4 个答案:

答案 0 :(得分:7)

在C ++ 0x中,PODness的概念被分解为几个有用的类别:

  

平易可复制的类是一个类(草案3242,第[class]部分):

     
      
  • 没有非平凡的副本构造函数(12.8),
  •   
  • 没有非平凡的移动构造函数(12.8),
  •   
  • 没有非平凡的复制赋值运算符(13.5.3,12.8),
  •   
  • 没有非平凡的移动赋值运算符(13.5.3,12.8)和
  •   
  • 有一个简单的析构函数(12.4)。
  •   
     

普通类是一个具有普通默认构造函数(12.1)并且可以轻易复制的类。

     

[注意:特别是,一个简单的可复制或普通的类没有虚函数或虚拟基   类。 - 结束记录]

     

标准布局类是一个类:

     
      
  • 没有非标准布局类(或此类类型的数组)或引用类型的非静态数据成员,
  •   
  • 没有虚函数(10.3),没有虚基类(10.1),
  •   
  • 对所有非静态数据成员具有相同的访问控制(第11条),
  •   
  • 没有非标准布局基类
  •   
  • 要么在最派生类中没有非静态数据成员,要么最多只有一个基类   非静态数据成员,或者没有包含非静态数据成员的基类,
  •   
  • 没有与第一个非静态数据成员相同类型的基类。
  •   

琐碎的构造函数,赋值运算符和析构函数的要求分散在第12节“特殊成员函数”[special]中。

答案 1 :(得分:4)

C ++ 03中POD的概念确实过于严格。在C ++ 0x中,POD被推广为包括您描述的对象。所以不用担心,你可以把它命名为POD。在Wikipedia上看到一个不错的总结。

答案 2 :(得分:1)

您的示例的一个问题是它具有隐式声明的,无关紧要的析构函数。尽管有这个名字,但实施并不是AFAIK禁止在非POD类的简单析构函数中做某事。

因此,合法地执行一些奇怪的实现,您的类ex_struct可能会表现出与以下内容等效的运行时行为:

struct weird_ex_struct
{
  int a,b,c,d;
  weird_ex_struct() : a(123), aptr(&a) { }
  weird_ex_struct(const weird_ex_struct &o) : 
    a(o.a), b(o.b), c(o.c), d(o.d), aptr(&a) {}
  weird_ex_struct &operator=(const weird_ex_struct &o) {
    a = o.a; //etc
    aptr = &a;
    return *this;
  }
  ~weird_ex_struct() {
    if (aptr != &a) std::terminate();
  }
private:
  int *aptr;
}

我说运行时行为,因为weird_ex_struct有一个非平凡的析构函数,这会影响它如何合法使用(不是在联合中,一方面)。另外我认为有一些标准方法可以在编译时检测私有数据成员的存在。但是只要实现可以保持这个东西是秘密的,除非你做了一些未定义的事情(memcpy非POD对象),那么之后就可以让你感到惊讶。

显然,如果weird_ex_structmemcpy复制,那么当它被销毁时会发生奇怪的事情。

没有明显的理由要求实现这一点,但标准保留非POD类广泛用于实现奇怪的事情。不确定这是因为他们认为有人会想到一些有用的怪异,或者只是因为他们没有像C ++ 0x那样定义标准布局

[编辑:约翰内斯指出我对琐碎的析构函数有误 - 由于处理对象生命周期的标准部分中提出的原因,实现不能在依赖于内容的琐碎析构函数中做事。对象的记忆。如果明确地调用析构函数,他们可能会这样做,我不确定。

然而,事实仍然是标准允许实现使用非POD对象做很多疯狂的事情,并且只要你编写构造函数,就打开那扇门。]

答案 3 :(得分:0)

是的,使用memcpy进行复制是安全的,因为构造函数只能初始化值。