c++ - 不同的隐式生成函数之间是否存在可观察到的语义差异?

标签 c++ language-lawyer

我一直在阅读 C++ 标准,试图了解平凡、简单和隐式定义的构造函数/赋值运算符/析构函数之间是否存在任何可观察到的差异。从我目前的理解来看,似乎没有什么区别,但这似乎很奇怪,为什么在无关紧要的情况下花这么多时间定义它们?
作为一个特定的具体示例,请考虑复制构造函数。

  • 如果所有字段和基类都是平凡的,那么平凡复制构造函数会逐个字段地复制所有字段和基类。
  • 否则,隐式生成的复制构造函数:“按初始化顺序执行基本成员和非静态成员的完整成员拷贝”。

  • 如果我理解正确,如果一个类具有所有琐碎的基础和字段,但具有默认的复制构造函数,那么默认的复制构造函数将与普通构造函数做完全相同的事情。甚至初始化顺序在这里似乎都不相关,因为这些字段都是不相交的(因为平凡意味着没有 virtual 基类)。
    有没有一个例子,一个简单的复制构造函数会做一些与显式默认的复制构造函数不同的事情?
    通常,相同的逻辑似乎也适用于其他构造函数和析构函数。由于数据竞争的可能性,分配的参数有点复杂,但如果类实际上是微不足道的,那么所有这些似乎都是标准未定义的行为。

    最佳答案

    不完全是关于实际特殊成员函数本身*的行为,但请考虑以下事项:

    struct Normal
    {
        int a;
    };
    
    static_assert(std::is_trivially_move_constructible_v<Normal>);
    static_assert(std::is_trivially_copy_constructible_v<Normal>);
    static_assert(std::is_copy_constructible_v<Normal>);
    
    这一切似乎都很好。
    现在考虑以下几点:
    struct Strange
    {
        Strange() = default;
        Strange(Strange&&) = default; 
    };
    
    static_assert(std::is_trivially_move_constructible_v<Strange>);
    static_assert(!std::is_trivially_copy_constructible_v<Strange>);
    static_assert(!std::is_copy_constructible_v<Strange>);
    
    唔。 的单纯行为显式默认移动构造函数不允许对象复制构造!
    为什么是这样?
    因为,即使编译器仍然是 定义 Strange 的移动构造函数,它仍然是 用户声明 移动构造函数,它禁用复制特殊成员函数的生成。
    当您拥有用户声明版本的特殊成员函数时,标准非常挑剔会生成哪些特殊成员函数,因此最好坚持使用 Rule of Five or Zero .
    Live Demo

    额外学分
    通过显式默认 Strange 的默认构造函数,它不再是聚合类型(而 Normal 是)。这开启了一个完全不同的关于初始化的蠕虫。

    *因为据我所知,显式默认的特殊成员函数的行为与该函数的普通版本(或者更确切地说, it's the other way around )相同。但是,我必须注意标准措辞的一个特点;在讨论隐式声明的复制构造函数时,标准忽略了“隐式声明为默认值”,就像它对默认和移动构造函数所做的那样。我相信这是一个小错误。

    关于c++ - 不同的隐式生成函数之间是否存在可观察到的语义差异?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63608199/

    相关文章:

    c++ - 带有初始化的 Vector<int> 工厂不工作

    c++ - 1 小时后首次连接后 Tcp 接受失败

    c++ - 全局和嵌套匿名命名空间中的歧义访问标识符

    c - stdatomic.h 的名称是否与将映射到句点前的八个有效字符的(潜在)限制相矛盾?

    c++ - 由于删除了模板化左值转换运算符,clang 或 gcc 中可能存在错误?

    c++ - 非多态类型派生类型的虚拟基础

    c++ - 容器 STL 的 typeid

    c++ - 真正的位置字符串格式?

    c++ - 是否可以默认使用 UB?

    c++ - 使用 DAO 获取 Access 数据库的拷贝 ID