标准布局和不可复制属性

Standard layout and non-copyable property

本文关键字:可复制 属性 布局 标准      更新时间:2023-10-16

C++11,§9/7:

标准布局类是这样一个类:

  • 不具有非标准布局类(或此类类型的数组)或引用类型的非静态数据成员
  • 没有虚拟函数,也没有虚拟基类
  • 对所有非静态数据成员具有相同的访问控制
  • 没有非标准布局基类
  • 在最派生的类中没有非静态数据成员,并且最多有一个基类具有非静态数据会员,或者没有基类具有非静止数据会员,以及
  • 没有与第一个非静态数据成员类型相同的基类

那么,有没有办法让一个具有标准布局的类不可复制?如果是,如何?

从boost::noncopyable私有继承将不起作用,因为它使复制构造函数成为私有的(因此不是标准布局)。boost::noncopable的实现是这样的:

  class noncopyable
  {
   protected:
      noncopyable() {}
      ~noncopyable() {}
   private:  // emphasize the following members are private
      noncopyable( const noncopyable& );
      const noncopyable& operator=( const noncopyable& );
  };

由于私有部分的原因,它不是一个标准布局类。我还注意到,如果私有继承违反了任何标准的布局规则。


#include <boost/noncopyable.hpp>
#include <iostream>
const int N = 50;
struct A
{
    int data[N];
};
struct B : private boost::noncopyable
{
    int data[N];
};
struct C
{
    A data[10];
};
struct D : private boost::noncopyable
{
    B data[10];
};
int main() {
    std::cout<<sizeof(A)<<std::endl;
    std::cout<<sizeof(B)<<std::endl;
    std::cout<<sizeof(C)<<std::endl;
    std::cout<<sizeof(D)<<std::endl;
}

输出为:

200
200
2000
2004

上面的示例显示,从boost::noncopyable私下继承会将类更改为不符合标准布局。我不确定这是一个g++错误(我使用的是g++4.6.1),还是某种程度上违反了标准。

我认为这里有一个混淆:

  • 标准布局属性受属性(且仅受属性)影响
  • 可复制属性受方法(它们的存在、不存在和可访问性)的影响

这两个概念是正交的。

更新:

以下显示与boost::noncopyable:完全相同的行为

#include <iostream>
struct foo {};
struct B : foo { int data; };
struct D : foo { B data; };
int main() {
  D d;
  std::cout << (char*)(&d.data) - (char*)(&d) << "n";
}

结果是CCD_ 3。

我相信这是因为:

  • 没有与第一个非静态数据成员类型相同的基类

事实上,实验表明,在data之前在D中引入int a;不会增加其大小。我认为Bfoo继承的事实意味着data(第一个非静态数据成员)被认为是与fooD的基类)相同的类型。

这导致了歧义:如果编译器没有引入这种填充,foo* f = &d将具有与foo* g = &b.data;相同的地址。

要使类不可复制,需要做两件事:

  1. 将复制构造函数设为私有构造函数
  2. 将分配运算符设为私有运算符。(如果它被分配了与类本身相同的另一种类型)

您不需要从某个boost类继承就可以获得该行为。

我想补充一点,谁在乎一些花哨的"标准布局"想法呢。规划你需要的东西,不要屈服于这种极端的空间理论。