C++核心准则​NR.5:不要使用两阶段初始化

NR.5: Don't use two-phase initialization

NR.5:不要使用两阶段初始化

 

 

Reason(原因)

Splitting initialization into two leads to weaker invariants, more complicated code (having to deal with semi-constructed objects), and errors (when we didn't deal correctly with semi-constructed objects consistently).

将初始化分为两部分会导致不变性较弱,代码更复杂(必须处理半结构化对象)和错误(当我们不能始终如一地正确处理半结构化对象时)。

 

Example, bad(反面示例)

// Old conventional style: many problems

class Picture
{
    int mx;
    int my;
    char * data;
public:
    // main problem: constructor does not fully construct
    Picture(int x, int y)
    {
        mx = x;         // also bad: assignment in constructor body
                        // rather than in member initializer
        my = y;
        data = nullptr; // also bad: constant initialization in constructor
                        // rather than in member initializer
    }

    ~Picture()
    {
        Cleanup();
    }

    // ...

    // bad: two-phase initialization
    bool Init()
    {
        // invariant checks
        if (mx <= 0 || my <= 0) {
            return false;
        }
        if (data) {
            return false;
        }
        data = (char*) malloc(mx*my*sizeof(int));   // also bad: owning raw * and malloc
        return data != nullptr;
    }

    // also bad: no reason to make cleanup a separate function
    void Cleanup()
    {
        if (data) free(data);
        data = nullptr;
    }
};

Picture picture(100, 0); // not ready-to-use picture here
// this will fail..
if (!picture.Init()) {
    puts("Error, invalid picture");
}
// now have a invalid picture object instance.

Example, good(范例)

class Picture
{
    int mx;
    int my;
    vector<char> data;

    static int check_size(int size)
    {
        // invariant check
        Expects(size > 0);
        return size;
    }

public:
    // even better would be a class for a 2D Size as one single parameter
    Picture(int x, int y)
        : mx(check_size(x))
        , my(check_size(y))
        // now we know x and y have a valid size
        , data(mx * my * sizeof(int)) // will throw std::bad_alloc on error
    {
        // picture is ready-to-use
    }

    // compiler generated dtor does the job. (also see C.21)

    // ...
};

Picture picture1(100, 100);
// picture is ready-to-use here...

// not a valid size for y,
// default contract violation behavior will call std::terminate then
Picture picture2(100, 0);
// not reach here...

Alternative(代替选项)

  • Always establish a class invariant in a constructor.

    始终在构造函数中建立类不变式。

  • Don't define an object before it is needed.

    不要在需要之前定义对象。

     

原文链接

https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#nr5-dont-use-two-phase-initialization

 

新书介绍

《实战Python设计模式》是作者最近出版的新书,拜托多多关注!

C++核心准则​NR.5:不要使用两阶段初始化

本书利用Python 的标准GUI 工具包tkinter,通过可执行的示例对23 个设计模式逐个进行说明。这样一方面可以使读者了解真实的软件开发工作中每个设计模式的运用场景和想要解决的问题;另一方面通过对这些问题的解决过程进行说明,让读者明白在编写代码时如何判断使用设计模式的利弊,并合理运用设计模式。

对设计模式感兴趣而且希望随学随用的读者通过本书可以快速跨越从理解到运用的门槛;希望学习Python GUI 编程的读者可以将本书中的示例作为设计和开发的参考;使用Python 语言进行图像分析、数据处理工作的读者可以直接以本书中的示例为基础,迅速构建自己的系统架构。

 


 

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

关注微信公众号【面向对象思考】轻松学习每一天!

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

 

C++核心准则​NR.5:不要使用两阶段初始化

 

上一篇:[LeetCode] 1026. Maximum Difference Between Node and Ancestor 结点与其祖先之间的最大差值


下一篇:跳跃游戏