Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/user-interface/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 初始化列表的使用_C++_Constructor_Initializer List - Fatal编程技术网

C++ 初始化列表的使用

C++ 初始化列表的使用,c++,constructor,initializer-list,C++,Constructor,Initializer List,我已经学会了什么是一个,如何去做,但我仍然在想一件事 使用初始化列表初始化类的变量与自己在构造函数中初始化类的变量之间有什么区别(如果有) 例如 VS 这仅仅是一种使代码更易于阅读和编写的设计习惯,还是有其他具体原因?如果这些变量是基本类型,它们不是常量,也不是引用,那么就没有区别了 如果您的成员是引用或const,则必须对其进行初始化,并且只能通过初始化列表中的变量进行初始化,原因与禁止您创建基本类型的未初始化引用或const变量的原因相同: int& x; // ERROR! con

我已经学会了什么是一个,如何去做,但我仍然在想一件事

使用初始化列表初始化类的变量与自己在构造函数中初始化类的变量之间有什么区别(如果有)

例如

VS


这仅仅是一种使代码更易于阅读和编写的设计习惯,还是有其他具体原因?

如果这些变量是基本类型,它们不是常量,也不是引用,那么就没有区别了

如果您的成员是引用或
const
,则必须对其进行初始化,并且只能通过初始化列表中的变量进行初始化,原因与禁止您创建基本类型的未初始化引用或
const
变量的原因相同:

int& x; // ERROR!
const int y; // ERROR!
初始化后不能重新分配这些对象:因此,必须对它们进行值初始化,并且不允许在未初始化这些成员变量的情况下执行类的构造函数体

因此,当您有选择时,对于基本类型,两种形式之间没有区别-请记住,在某些情况下,您没有选择

另一方面,如果您的成员变量是类类型,那么区别在于没有初始化列表,它们将被默认构造(如果可能的话),然后在构造函数的主体中赋值;使用初始化列表,它们将直接使用您指定的参数构造

请注意,C++11为您提供了一种额外的可能性:

class MyClass {
public:
    int m_classID = -1;
    void *m_userdata = nullptr;
};

有些东西没有MIL就无法初始化,例如引用成员

class MyClass {
public:

    MyClass(MyOtherClass& otherClass)
         : m_classID(-1)
         , m_userdata(otherClass)
    { 
    }

    int m_classID;
    MyOtherClass& m_userdata;
};

此外,它是初始化常量成员的唯一方法。

初始化器列表允许您调用成员变量的构造函数

如果在构造函数体中初始化,则调用的是
操作符=
(赋值),而不是构造函数

这种差异类似于这两种形式之间的差异:

int three(3);            // Constructor argument
int three; three = 3;    // Assignment after construction
这对于没有默认构造函数的成员(即没有参数的构造函数)和在创建值时必须设置值的成员(如引用和常量)都会有所不同


因此,只能初始化构造函数体中的某些类型的成员;但所有种类的成员都可以在初始值设定项列表中初始化。这一点,以及默认构造函数没有为初始值设定项列表初始化成员调用的事实(这对复杂对象有区别,但对整数来说并不重要),意味着如果有选择,通常最好使用初始值设定项列表。

对于您给出的情况,没有直接的区别-初始值设定项列表实际初始化的顺序(成员声明的顺序)略有不同,在第二个示例中,如果您将表示
m_classID=-1
的行替换为
m_userdata=0
,则它们确实会以相反的顺序初始化

不能在初始值设定项列表之外初始化引用或常量值,因此:

class bleh
{
   int& m_x;
   bleh(int x)
   {
      m_x = x;
   }
};
会给你一些错误

class bleh
{
   int& m_x;
   bleh(int x): m_x(x)
   {
   }
};

是正确的方法。

初始化列表更可取,因为

  • 您可以将它们与引用一起使用
  • 您可以避免运行默认构造函数+运算符=,而只运行速度更快的必需构造函数。如果默认构造函数是私有的,则必须使用初始值设定项列表

  • 只是想指出c++11中的一个区别:

    class MyClass {
    public:
        MyClass(std::string str) : m_str(str) { }
    private:
        std::string m_str;
    };
    
    等于做

    class MyClass {
    public:
        MyClass(std::string str) { m_str = std::move(str); }
    private:
        std::string m_str;
    };
    
    其中:

    class MyClass {
    public:
        MyClass(std::string str) { m_str = str; }
    private:
        std::string m_str;
    };
    
    正在仅调用赋值运算符

    我遇到这个问题是因为我在Lua中初始化对象,当它们被销毁时,字符串被清理了两次,导致sigtrap,因为Lua认为它控制了传入字符串的所有权,但一旦它被移动,情况就不再如此了


    我知道这并不能完全回答这个问题,但其他答案并不能直接回答这个问题。

    尝试使用引用或常量成员。@chris-你是什么意思?可能重复@Matteo,我现在有点晚了,但Andy的答案解决了这个问题。
    class MyClass {
    public:
        MyClass(std::string str) { m_str = std::move(str); }
    private:
        std::string m_str;
    };
    
    class MyClass {
    public:
        MyClass(std::string str) { m_str = str; }
    private:
        std::string m_str;
    };