2

C++11,第 9/7 节:

标准布局类是这样的类:

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

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

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

  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),或者该标准在某种程度上被违反了。

4

2 回答 2

4

我认为这里有一个混淆:

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

这两个概念是正交的。

更新:

以下显示了完全相同的行为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";
}

结果是4

我相信这是因为:

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

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

这会导致歧义:foo* f = &d将具有相同的地址,就foo* g = &b.data;好像编译器没有引入此填充一样。

于 2012-01-31T10:43:46.280 回答
0

要使您的课程不可复制,您需要做两件事:

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

您不需要为了获得这种行为而从某个 boost 类继承。

我可以补充一下,谁在乎一些花哨的“标准布局”想法。编程你需要的东西,不要屈服于这个极端的空间理论。

于 2012-01-31T10:38:16.497 回答