标准布局和不可复制属性
Standard layout and non-copyable property
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;
不会增加其大小。我认为B
从foo
继承的事实意味着data
(第一个非静态数据成员)被认为是与foo
(D
的基类)相同的类型。
这导致了歧义:如果编译器没有引入这种填充,foo* f = &d
将具有与foo* g = &b.data;
相同的地址。
要使类不可复制,需要做两件事:
- 将复制构造函数设为私有构造函数
- 将分配运算符设为私有运算符。(如果它被分配了与类本身相同的另一种类型)
您不需要从某个boost类继承就可以获得该行为。
我想补充一点,谁在乎一些花哨的"标准布局"想法呢。规划你需要的东西,不要屈服于这种极端的空间理论。
相关文章:
- 简单可复制与可简单复制
- 将可选属性表示为 C++类成员
- reinterpret_cast,只读访问,简单的可复制类型,会出什么问题?
- 对于参加可复制和可移动类的访问者来说,应该有多少过载?
- 可变参数宏:无法通过"..."传递非平凡可复制类型的对象
- 为什么 std::atomic<std::string> 会给出微不足道的可复制错误?
- 我可以隐式地创建一个琐碎的可复制类型吗
- 是std::memcpy在不同的可复制类型之间的未定义行为
- 为什么一对常量是微不足道的可复制的,而对不是?
- 在一个微不足道的可复制结构中,移动语义应该实现吗?
- QML / C++可选属性
- 在 Spirit X3 中使用布尔属性而不是可选属性
- 防止作用域枚举可复制/可移动
- C :对象上的可复制视图
- 防御性地应用 std::move 到平凡可复制的类型是否不可取
- 为什么 std::function 本身是可复制构造的类型?
- C++不可复制的 lambda 的行为是可复制的
- 错误:无法通过'...'传递非平凡可复制类型的对象'class boost::filesystem::path'
- 不能让类是微不足道的可复制的。我做错了什么?
- 使用临时存储区复制普通的可复制类型:允许吗