当前位置: 首页 > 知识库问答 >
问题:

具有用户定义的构造函数的普通类型和POD类型

宦翔飞
2023-03-14

首先,这更像是一个理智检查问题,以获得比我更精通语言标准深度的人的认可。

假设我有以下类型(尽管我忽略了任何非构造函数和非赋值成员函数):

template<typename E> struct half_expr
{
};

class half : public half_expr<half>
{
public:
    half();
    explicit half(float);
    template<typename E> half(const half_expr<E>&);

    half& operator=(float);
    template<typename E> half& operator=(const half_expr<E>&);

private:
    half(std::uint16_t, bool);

    std::uint16_t data_;
};

好吧,在任何合理的实现中,half在内存中都不应该是普通的std::uint16_t。但我对标准的保证很感兴趣。以下是我根据C 98/03定义POD的理由:

  • 一半不能是 POD 类型,因为它具有非公共字段、基类和用户定义的构造函数。

和C 11的losened/扩展定义:

>

  • 它应该是微不足道的可复制的,因为它只隐式生成了复制/移动构造函数/赋值,但只要这些浮点数和模板版本不以任何方式计算在内,我就不完全确定。

    它也应该是标准布局,因为它只有一个基本类型的私有字段和一个空的非虚拟基类(在任何标准中都应该是POD,对吗?)

    唯一阻碍POD-分类的是它不是普通的缺省可构造的,这可能通过使用C 11的< code>half() = default语法来克服。

    我非常简单的问题是:我的基本原理是完全正确的,还是我在定义中忽略或误解了任何东西,尤其是考虑到用户定义的构造函数和赋值在某种程度上阻碍了分类为简单的可复制?

    注意:即使您有将此委托给一些关于POD和标准布局类型的可能重复(我可以完全理解)的冲动,回答我的实际问题的简单评论仍然会很好,因为这仅仅是一个理智的检查,这可能对你来说很简单或超级浮夸,但我只是想保持安全。

  • 共有1个答案

    梁学真
    2023-03-14

    是的,一半是标准布局(9/7):基类为空,派生类对所有非静态数据具有相同的权限改造,没有虚拟,也没有非标准布局的基或成员,基是与第一个非静态数据成员不同的类型。

    您定义的构造函数和赋值运算符不是复制(或移动)构造函数和赋权,因此它们与类是否可以普通复制无关。

    默认构造函数是非同寻常的,因为它是用户提供的(12.1/5),因此该类并不平凡。

    拷贝/移动都是微不足道的,因为数据成员和空基具有微不足道拷贝/移动(12.8/12)。析构函数也是如此,因此该类通常是可复制的。

    所以我相信你的html" target="_blank">分析是正确的——去掉无参数构造函数,你在C 11中就有了一个POD类(但在C 98中没有)。

    正如Luc所说,标准中没有保证POD类不包含填充,即使它只有一个数据成员。

    在C 03中,空基类优化是允许的,而不是必需的,所以一个质量差但符合要求的C 03实现肯定会给你sizeof(半)==sizeof(half_expr

    在C 11中,布局兼容的规则实际上要求应用空基类优化——两个标准布局类型,其中一个有基类,另一个没有,是布局兼容的(9.2/17),布局兼容的类型可以通过联合读取(9.2/19),这意味着它们必须具有相同的布局。填充仍然是允许的,但是没有意义。

    撇开标准不谈,您的实现可能来自也可能不使用 C ABI,该 ABI 会告诉您 POD 类的外观。如果是这样,我预计尽管 ABI 可能还没有为 C 11 提供最新的版本,但可以肯定的是,该实现将使所有标准布局类看起来都与 POD 类的定义相同,而不管它们是否也是微不足道的(并且它将进行 EBC 优化)。这就是标准布局的要点:“类像C结构一样布局”。

    我认为实现也被允许任意决定所有类类型必须是4对齐的,在这种情况下,你会再次得到填充。不过,我认为期望这样做是不合理的,因为我能想到的唯一动机是,你在一些奇怪的架构上,4对齐的指针可以小于char*

     类似资料:
    • 我试图在静态编程语言中创建一个非常简单的泛型NDArray类,它将lambda表达式作为初始化函数。 典型的用法是: 我的问题是Kotlin编译器抱怨构造函数中值的初始化 通过说“不能使用‘T’作为具体化类型参数。改用类”。为什么? 编辑: 如果我用我自己的MyArray替换静态编程语言Array实现,它会编译: 不确定为什么静态编程语言对待MyArray与常规数组不同,当两者具有相同的构造函数时

    • 无论我用什么方法尝试,无论是主构造函数还是次构造函数,我都不知道如何在kotlin中声明一个带有超类和构造函数的新类。 这是我最想做的,但它给出了一个错误,期望成员声明。 这是我认为主要构造函数的外观,但它给出了相同的错误。在Internet上搜索没有帮助,我只能找到第二个示例。 那么,用一个超类和它的一个构造函数创建一个类的所有有效方法是什么呢?

    • 问题内容: 如果我有一个像这样的抽象类: 还有一些从Item派生的类是这样的: 我不明白为什么我不能使用泛型调用构造函数: 我知道可以有一个没有构造函数的类型,但是这种情况是不可能的,因为Pencil具有没有参数的构造函数,而Item是抽象的。但是我从eclipse中得到了这个错误: 无法实例化 我不明白为什么的 T类型 ,以及如何避免这种情况? 问题答案: 无法使用Java类型系统来强制类层次结

    • 对于Cassandra中的用户定义聚合函数,什么可以作为INITCOND?我只见过具有简单类型(例如元组)的示例。 我为聚合函数中的状态对象提供了以下类型: 当我省略INITCOND时,我得到一个JavaNullPointerException。

    • 问题内容: 我的测试框架中有一个方法可以创建类的实例,具体取决于传入的参数: 问题是,如果构造函数具有基本类型,则这将不起作用,如下所示: 结果是: 原始int会自动装箱到对象版本中,但是如何返回它们以调用构造函数? 问题答案: 使用代替。 根据Javadocs,这是“表示原始类型的Class实例”。 您也可以使用。这是的快捷方式。不仅是类,甚至对于原始类型,您都可以用Java表示。