不存在默认的构造函数_C++核心准则C.43:确保(值类型)可拷贝类有默认构造函数...

0b43b28836a5618ace9a9a2afe6c7391.png

C.43: Ensure that a copyable (value type) class has a default constructor

C.43:确保(值类型)可拷贝类有默认构造函数

Reason(原因)

Many language and library facilities rely on default constructors to initialize their elements, e.g. T a[10] and std::vector v(10). A default constructor often simplifies the task of defining a suitable moved-from state for a type that is also copyable.

很多语言和库设施依靠默认构造函数来初始化它们的元素,例如T a[0]和std::vectorv(10)。默认构造函数经常可以简化为可拷贝类定义适当的移出状态的工作。

Note(注意)

A value type is a class that is copyable (and usually also comparable). It is closely related to the notion of Regular type from EoP and the Palo Alto TR.

可拷贝(通常也是可比较)的类称为值类型。它和《编程原本》和《STL概念设计》中提到的正规类型之间的联系非常紧密。

正规类型:https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#SS-concrete

编程原本:http://elementsofprogramming.com/

STL概念设计:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3351.pdf

Example(示例)

class Date { // BAD: no default constructorpublic:    Date(int dd, int mm, int yyyy);    // ...};vector vd1(1000);   // default Date needed herevector vd2(1000, Date{Month::October, 7, 1885});   // alternative

The default constructor is only auto-generated if there is no user-declared constructor, hence it's impossible to initialize the vectorvd1in the example above. The absence of a default value can cause surprises for users and complicate its use, so if one can be reasonably defined, it should be.、

默认构造函数只有在不存在用户定义构造函数时才会自动生成,因此像上面代码中vector vd1那样的初始化是不可能的。默认值的缺失可能令用户感到意外并且增大使用的难度,因此如果有可能合理地定义它,就那样做。

Date is chosen to encourage thought: There is no "natural" default date (the big bang is too far back in time to be useful for most people), so this example is non-trivial.{0, 0, 0} is not a valid date in most calendar systems, so choosing that would be introducing something like floating-point's NaN. However, most realistic Date classes have a "first date" (e.g. January 1, 1970 is popular), so making that the default is usually trivial.

选择日期类是为了推进思考:不存在"自然"的默认日期(对于大多数人来说,以宇宙大爆炸的时刻作为默认值需要将时间回退的太多了,不具备实际意义),因此这个例子不具备一般性。{0,0,0}在大多数日历系统中都不是合法的日期,因此选择它将会引起类似浮点数的NaN问题。

NaN:不是数字,或者说无效数字。

class Date {public:    Date(int dd, int mm, int yyyy);    Date() = default; // [See also](#Rc-default)    // ...private:    int dd = 1;    int mm = 1;    int yyyy = 1970;    // ...};vector vd1(1000);

Note(注意)

A class with members that all have default constructors implicitly gets a default constructor:

如果一个类的所有成员都有默认构造函数,那么这个类也隐式得到一个默认构造函数。

struct X {    string s;    vector v;};X x; // means X{{}, {}}; that is the empty string and the empty vector

Beware that built-in types are not properly default constructed:

注意:内置类型没有被正确地默认构造:

struct X {    string s;    int i;};void f(){    X x;    // x.s is initialized to the empty string; x.i is uninitialized    cout << x.s << ' ' << x.i << '';    ++x.i;}

Statically allocated objects of built-in types are by default initialized to 0, but local built-in variables are not. Beware that your compiler may default initialize local built-in variables, whereas an optimized build will not. Thus, code like the example above may appear to work, but it relies on undefined behavior. Assuming that you want initialization, an explicit default initialization can help:

静态分配的内置类型被默认初始化为0,办事局部的内置类型没有。注意你的编译器有可能初始化局部的内置类型变量,尽管优化状态的编译不会。因此上面示例中的代码看起来可以动作,但是者依靠(编译器,译者注)没有定义的行为。如果你需要初始化,明确的默认初始化可以帮忙:

struct X {    string s;    int i {};   // default initialize (to 0)};

Notes(注意)

Classes that don't have a reasonable default construction are usually not copyable either, so they don't fall under this guideline.

不包含合理的默认构造动作的类通常也不是可拷贝的,因此它们不算对本准则的违反。

For example, a base class is not a value type (base classes should not be copyable) and so does not necessarily need a default constructor:

例如,基类不是值类型(基类不应该可拷贝)而且不需要默认构造函数。

// Shape is an abstract base class, not a copyable value type.// It may or may not need a default constructor.struct Shape {    virtual void draw() = 0;    virtual void rotate(int) = 0;    // =delete copy/move functions    // ...};

A class that must acquire a caller-provided resource during construction often cannot have a default constructor, but it does not fall under this guideline because such a class is usually not copyable anyway:

一个类如果必须在构造期间要求调用者提供资源,通常不能拥有默认构造函数,但是它没有违反本准则,因为这样的类通常无论如何也是不能拷贝的。

// std::lock_guard is not a copyable value type.// It does not have a default constructor.lock_guard g {mx};  // guard the mutex mxlock_guard g2;      // error: guarding nothing

A class that has a "special state" that must be handled separately from other states by member functions or users causes extra work (and most likely more errors). Such a type can naturally use the special state as a default constructed value, whether or not it is copyable:

有的类具有某种“特殊状态”,必须通过成员函数或者用户引发(最有可能是错更多的错误)的特别动作彼此分开进行处理。这样的类型可以自然地使用特殊状态作为默认构造的初始值,不管它是否是可拷贝的。

// std::ofstream is not a copyable value type.// It does happen to have a default constructor// that goes along with a special "not open" state.ofstream out {"Foobar"};// ...out << log(time, transaction);

Similar special-state types that are copyable, such as copyable smart pointers that have the special state "==nullptr", should use the special state as their default constructed value.

类似的可拷贝的特殊状态类型,例如包含“==nullprt"这样的特殊状态的可拷贝的智能指针,应该使用特殊状态作为它们默认构造的初始值。

However, it is preferable to have a default constructor default to a meaningful state such as std::strings "" and std::vectors {}.

然而,更可取的做法是让默认构造函数默认生成一个有意义的状态,例如std::string的“”和std::vectors{}。

Enforcement(实施建议)

  • Flag classes that are copyable by = without a default constructor如果类实现了赋值运算符但却没有构造函数,进行提示。
  • Flag classes that are comparable with == but not copyable如果类可以通过比较运算符进行比较但却不是可拷贝的,进行提示。

原文链接

https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#c43-ensure-that-a-copyable-value-type-class-has-a-default-constructor


觉得本文有帮助?请分享给更多人。

更多文章请关注微信公众号【面向对象思考】!

面向对象开发,面向对象思考!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: C++不存在默认构造函数是指在定义一个C++类时,如果没有显式地声明或定义默认构造函数,那么编译器就不会为该类生成默认构造函数默认构造函数是一个没有任何参数的构造函数,它负责在创建对象时,给对象的成员变量初始化。当我们没有定义任何构造函数时,编译器会默认生成一个默认构造函数。但是,如果我们在类中显式定义了任何其他构造函数,编译器就不会再生成默认构造函数了。 当一个类没有默认构造函数时,我们在创建对象时必须显式地调用有参构造函数来进行对象的初始化。如果我们没有定义有参构造函数,那么编译器会报错,因为它无法自动创建默认构造函数。 为什么C++不存在默认构造函数呢?这是因为C++允许我们在定义类时通过构造函数对对象进行初始化,这样可以确保对象的合法性和一致性。但是,如果自动生成默认构造函数,那么对象就会使用默认进行初始化,可能会导致对象的成员变量处于一个不合理的状态,进而引发错误。 为了避免这种错误,C++规定没有显式定义或声明默认构造函数的类,是无法使用默认构造函数的。因此,我们必须显式地定义或声明一个有参构造函数来对对象进行初始化。这样可以保证对象始终处于一个合理的状态,提高程序的稳定性和安全性。 ### 回答2: C++类如果没有显式声明构造函数,编译器会为其生成一个默认构造函数。然而,如果类中有一些特殊的成员、基类或者虚函数,编译器就无法生成默认构造函数。 当类中存在有以下情况时,编译器无法生成默认构造函数: 1. 类的成员或基类没有默认构造函数:如果类的成员或者基类没有默认构造函数,编译器无法通过自动生成的默认构造函数来初始化这些成员或者基类,因此无法生成默认构造函数。 2. 类定义了带参数的构造函数:如果类中定义了任何构造函数(不论是默认参数构造函数还是重载的构造函数),编译器会认为你提供的构造函数相对于默认构造函数更为重要,所以不会再为类生成默认构造函数。 3. 类定义了虚函数:当类中定义了虚函数时,编译器无法自动生成默认构造函数,因为默认构造函数无法初始化虚函数的相关信息(例如虚函数表)。 为了解决类没有默认构造函数的问题,可以手动为类编写一个构造函数来完成初始化工作,或者使用初始化列表来初始化类的成员或基类。总之,在需要使用默认构造函数的地方,我们需要手动为类提供一个默认构造函数,而不是依赖于编译器的默认构造函数。 ### 回答3: C++中,类不存在默认构造函数的意思是,在定义一个类时,如果没有显式地定义构造函数,那么编译器不会自动生成默认构造函数构造函数是用来初始化对象的特殊成员函数,它会在对象创建时自动调用。当我们没有为类定义任何构造函数时,编译器会自动生成一个默认构造函数。 然而,当我们显式地定义了一个或多个构造函数时,编译器就不会再自动生成默认构造函数了。这就是所谓的“类不存在默认构造函数”。 如果我们需要创建一个没有默认构造函数的类的对象,我们就必须显式地定义自己的构造函数,以确保对象可以被正确地初始化。否则,在实例化该类对象时将会产生编译错误。 得注意的是,当定义了至少一个自定义构造函数后,如果我们还想要使用默认构造函数,则需要手动显式地定义一个默认构造函数。 例如,下面是一个没有默认构造函数的类例子: ```cpp class MyClass { public: MyClass(int value) { // 构造函数的实现 } }; ``` 在这个例子中,我们定义了一个名为MyClass的类,它只有一个带有一个整型参数的构造函数。因此,如果我们在没有提供参数的情况下实例化MyClass的对象,将会出现编译错误。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值