前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C.43:保证(值类型)可拷贝类有默认构造函数

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

作者头像
面向对象思考
发布2020-03-25 16:10:27
4690
发布2020-03-25 16:10:27
举报

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<T> 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::vector<T>v(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(示例)

代码语言:javascript
复制
class Date { // BAD: no default constructor
public:
    Date(int dd, int mm, int yyyy);
    // ...
};

vector<Date> vd1(1000);   // default Date needed here
vector<Date> 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:不是数字,或者说无效数字。

代码语言:javascript
复制
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<Date> vd1(1000);

Note(注意)

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

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

代码语言:javascript
复制
struct X {
    string s;
    vector<int> v;
};

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

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

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

代码语言:javascript
复制
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 << '\n';
    ++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,但是局部的内置类型没有。注意你的编译器有可能初始化局部的内置类型变量,但优化状态的编译不会。因此上面示例中的代码看起来可以动作,但是这依靠(编译器,译者注)没有定义的行为。如果你需要初始化,明确的默认初始化可以帮忙:

代码语言:javascript
复制
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:

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

代码语言:javascript
复制
// 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:

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

代码语言:javascript
复制
// std::lock_guard is not a copyable value type.
// It does not have a default constructor.
lock_guard g {mx};  // guard the mutex mx
lock_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:

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

代码语言:javascript
复制
// 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.

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

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


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

关注【面向对象思考】轻松学习每一天!

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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-12-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 面向对象思考 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • C.43: Ensure that a copyable (value type) class has a default constructor
    • C.43:确保(值类型)可拷贝类有默认构造函数
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档