标准布局和不可复制的属性

发布于 2024-12-29 18:03:32 字数 1470 浏览 2 评论 0原文

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++ bug(我使用的是 g++ 4.6.1),或者以某种方式违反了标准。

C++11, §9/7:

A standard-layout class is a class that:

  • has no non-static data members of type non-standard-layout class (or array of such types) or reference,
  • has no virtual functions and no virtual base classes,
  • has the same access control for all non-static data members,
  • has no non-standard-layout base classes,
  • either has no non-static data members in the most derived class and at most one base class with non-static data members, or has no base classes with non-static data members, and
  • has no base classes of the same type as the first non-static data member.

So, is there a way to make a class with standard layout non-copyable? If yes, how?

Inheriting privately from boost::noncopyable will not work, because it made copy constructor private (hence not a standard layout). The boost::noncopyable's implementation is like this :

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

Because of the private section, it is not a standard layout class. I am also note sure if private inheritance break any standard layout rule.


#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;
}

The output is :

200
200
2000
2004

The example above shows that inheriting privately from boost::noncopyable changes the class into NOT standard layout compliant.
I am not sure if this is a g++ bug (I am using g++ 4.6.1), or the standard is somehow violated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

冷夜 2025-01-05 18:03:32

我认为这里存在一个混淆:

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

这两个概念是正交的。

更新:

以下内容显示与 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

我相信这是因为:

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

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

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

I think there is a confusion here:

  • the standard layout property is affected by attributes (and only attributes)
  • the copyable property is affected by methods (their presence, absence and accessibility)

The two concepts are orthogonal.

UPDATE:

The following display the very same behavior that 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";
}

The result is 4.

I believe this is because of:

  • has no base classes of the same type as the first non-static data member.

Indeed, experiment shows that introducing a int a; in D prior to data does not increases its size. I think that the fact that B inherits from foo means that data (first non-static data member) is considered to be the same type as foo (base class of D).

This leads to an ambiguity: foo* f = &d would have the same address as foo* g = &b.data; if the compiler did not introduce this padding.

新雨望断虹 2025-01-05 18:03:32

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

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

您不需要仅仅为了获得该行为而继承某个 boost 类。

我可以补充一下,谁会关心一些奇特的“标准布局”想法。编写您需要的内容,不要屈服于这种极端的空间理论。

There are two things you need to do to make your class non copyable:

  1. Make the copy constructor private.
  2. Make the assignment operator private. (Where it gets assigned another type of the same kinds as the class itself).

You don't need to inherit from some boost class just to get that behavior.

And may I add, who cares about some fancy 'standard layout' idea. Program what you need and don't succumb to this extreme space theory.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文