首页 文章

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

提问于
浏览
17

在另一个question中,我错误地使用术语POD来指代那些没有通过标准查看的数据类型,并且找不到我想要的正确名称 . 我实际上也无法保证实际允许复制 .

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

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

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

所以我的问题是:

  • 具有memcpy的副本实际上是否确保对这些对象安全?

  • 如果是,那么为什么有关于memcpy和POD的特别说明?

  • 这种类型的数据是否有memcpy安全的名称?


我所说的对象类型的一个简单示例:

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

阅读C 0x草案,我的结构似乎是一个简单的可复制类(9.1) . 我相信这意味着memcpy是安全的 .

4 回答

  • 7

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

    一个简单的可复制类是一个类(草案3242,部分[类]):没有非平凡的复制构造函数(12.8),没有非平凡的移动构造函数(12.8),没有非平凡的复制赋值运算符( 13.5.3,12.8),没有非平凡的移动赋值运算符(13.5.3,12.8),并且有一个简单的析构函数(12.4) . 一个普通的类是一个具有普通默认构造函数(12.1)并且可以轻易复制的类 . [注意:特别是,一个简单的可复制或普通的类没有虚函数或虚基类 . - 结束注释]标准布局类是一个类:没有类型非标准布局类(或此类类型的数组)或引用的非静态数据成员,没有虚函数(10.3)且没有虚拟基础classes(10.1),对所有非静态数据成员具有相同的访问控制(第11章),没有非标准布局基类,在最派生类中没有非静态数据成员,最多只有一个基类具有非静态数据成员的类,或者没有具有非静态数据成员的基类,并且没有与第一个非静态数据成员相同类型的基类 .

    对于简单的构造函数,赋值运算符和析构函数的要求分散在第12节"Special Member Functions" [special] 中 .

  • 1

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

  • 4

    您的示例的一个问题是它具有隐式声明的,无关紧要的析构函数 . 尽管有这个名字,但实施并不是禁止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对象),那么它可以让你以后给你带来惊喜 .

    显然,如果用 memcpy 复制了 weird_ex_struct ,那么当它被销毁时会发生奇怪的事情 .

    有's no obvious reason for an implementation to do this, but the standard left non-POD classes wide open for implementations to do odd things. Not sure whether this is because they thought anyone would think of some useful weirdness, or just because they didn' t来定义像C 0x那样的标准布局 .

    [编辑:约翰内斯指出我对琐碎的析构函数的错误 - 由于处理对象生命周期的标准部分中提出的原因,实现不能在依赖于内存的内容的琐碎析构函数中做事情宾语 . 可能他们可以在明确调用析构函数时,我不确定 .

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

  • 0

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

相关问题