首页 > 解决方案 > 构造函数初始化列表与构造函数主体

问题描述

假设someString初始化有点复杂,因此我们编写了一个简单的成员函数stringInitialization()来在构造函数的主体中初始化someString

class DemoL {
private:

    int someNumber;
    std::string someString;

    void stringInitialization() {
        if (someNumber == 1) {
            someString = "FIRSTSTRING";
        } else if (someNumber == 2) {
            someString = "SECONDSTRING";
        } else {
            someString = "";
        }
    }

public:
    explicit DemoL(int rNumber) :
            someNumber(rNumber) {
        stringInitialization();
    }
};

这样,我假设someString将在构造函数的主体之前默认初始化,并且只有在此之后才会通过调用stringInitialization()对其进行修改。

所以,让我们稍微修改一下代码,以便我们在构造函数初始化列表中初始化someString :

class DemoL {
private:

    int someNumber;
    std::string someString;

    std::string stringInitialization() const {
        if (someNumber == 1) {
            return "FIRSTSTRING";
        } else if (someNumber == 2) {
            return "SECONDSTRING";
        } else {
            return "";
        }
    }

public:
    explicit DemoL(int rNumber) :
            someNumber(rNumber),
            someString(stringInitialization()) {}
};

您能否告诉我第二种变体是否更有效和正确?

标签: c++constructor

解决方案


你的假设是正确的。构造函数DemoL(int rNumber)需要能够默认构造成员someString,这没有问题,因为std::string它是默认可构造的。

显而易见的一点是,一个成员可能不是默认可构造的,在这种情况下,您必须对其进行初始化。

但即使是这样,默认构造它也可能会浪费资源,如果您在之后立即更改它,那么第二种选择对我来说似乎更好,因为它直截了当。

但是,由于stringInitialization按值返回,我会使用std::move,不,这实际上是一个坏主意,正如评论中所指出的那样。

所以作为一个结论:

  • 这两个代码是相同的someNumber
  • 第一个代码默认初始化someString(“调用” std::basic_string<...>::basic_string),然后分配它(调用std::basic_string<...>::operator=
  • 第二个代码在调用返回(调用)std::string时从字符串文字构造返回值,然后复制构造(调用);实际上发生复制省略是因为返回一个右值。stringInitializationbasic_string<...>::basic_string(const char*)someStringbasic_string<...>::basic_string(basic_string&&)stringInitialization

推荐阅读