【问题标题】:C++ default constructor syntax [duplicate]C ++默认构造函数语法[重复]
【发布时间】:2014-07-05 01:54:03
【问题描述】:

我对 C++ 中的默认构造函数有疑问。例如在 A 类中,使用默认构造函数 A(){};A() = default; 有什么区别?它们之间的一般区别是什么?

提前谢谢你!

【问题讨论】:

标签: c++ default-constructor


【解决方案1】:

在第一个声明中定义为默认的构造函数被认为不是用户提供的。这本质上就像在 C++03 中隐含。在聚合类中允许这样的构造函数声明。

struct ag {
    ag() = default;

    int a;
    double b;
};

struct nag {
    nag() {}

    int a;
    double b;
};

ag a = { 5, 12. }; // OK
nag na = { 5, 12. }; // error: not an aggregate and no appropriate constructor

此规则仅在 = default 出现在类中时适用。鉴于此类定义:

struct nag {
    nag();

    int a;
    double b;
}; 

那么这些构造函数定义确实是完全等价的:

nag::nag() {} // 1
nag::nag() = default; // 2

explicit 默认构造函数通常禁用空的复制列表初始化语法 (= {}),并将 {} 作为参数或 return 值。聚合中的显式默认和explicit 默认构造函数令人困惑地不受此规则的约束,因为聚合初始化比构造函数初始化具有更高的优先级。这提供了一种检测类是否为聚合的方法,但您可能不应该这样做。

struct sadistic {
    explicit sadistic() = default;

    // members
};

sadistic se = {}; // OK only if sadistic has no virtual functions, etc.

【讨论】:

    【解决方案2】:

    A() {}A() = default; 每 12.1p6 的默认构造函数的行为是相同的:

    隐式定义的默认构造函数执行类的一组初始化,这些初始化将由用户编写的该类的默认构造函数执行,没有 ctor-initializer (12.6.2) 和空的复合语句。

    区别在于:

    • 构造函数是否为constexpr(如果有效,则显式默认构造函数为constexpr),
    • 该类是否为聚合 (8.5.1p1),以及
    • 如果显式默认的默认构造函数很简单 (8.5p7),值初始化是否会导致调用默认构造函数。

    最后一点:

    #include <iostream>
    
    struct A { int i; A() = default; };
    struct B { int j; B() {} };
    
    int main() {
        int i = 42, j = 42;
        new (&i) A();
        new (&j) B();
        std::cout << i << std::endl;  // 0
        std::cout << j << std::endl;  // 42
    }
    

    所以你可能想要编写一个用户提供的非默认默认构造函数,例如,如果你的类有一些零初始化代价高昂的琐碎成员(例如一个大数组),但是这是一个非常小众的案例。

    【讨论】:

    • 当 A 被初始化时可能会有所不同,因为 A() = default 被认为不是用户定义的构造函数
    • @privatedatapublicchannel2 很好。
    • @privatedatapublicchannel2 我不太确定。你有例子吗?
    • @privatedatapublicchannel2:比这更复杂:8.4.2:如果函数是用户声明的,并且在第一次声明时没有显式默认或删除,则该函数是用户提供的。 i> 所以用户提供和用户声明是有区别的。此外,一个函数可以在第二个声明中声明为默认值,同时由用户提供和显式默认值! (但不是用户声明的)。 :-/
    • @juanchopanza 看到我上面的编辑。
    【解决方案3】:

    差别不大:

    旧语法(注意; 不需要):

    A() {}
    

    自 C++ 诞生之日起就可用。它会默认构造每个基类和成员变量。

    新的 C++11 语法:

    A() = default;
    

    完全一样,但它明确表示默认,因此您(或编译器)不必检查大括号是否真的为空。

    请注意,如果一个类没有声明的构造函数,编译器会为你添加一个。

    CORRECTION:如果删除默认构造函数有区别,即类隐式默认构造函数无效。在这种情况下,{} 是一个语法错误,而 =default 就像一个已删除的定义:

    struct S
    {
        int &r;  //non default constructible
    
        S() {} //error: uninitialized reference S::r;
        S() = default; //ok: deleted constructor
        S() = delete;  //also ok (but not both!)
    };
    

    【讨论】:

    • 当 A 被初始化时也可能存在差异
    猜你喜欢
    • 2020-05-14
    • 2020-05-19
    • 2013-11-06
    • 2014-05-15
    • 1970-01-01
    • 1970-01-01
    • 2015-12-01
    • 2015-07-24
    相关资源
    最近更新 更多