构造函数销毁成员变量

Constructor destroys member variables

本文关键字:变量 成员 构造函数      更新时间:2023-10-16

为什么第二次调用构造函数时会删除初始化的成员变量?

例:

class MyClass {
    private:
        unsigned myValue;
    public:
        MyClass(void)
        {
            this->myValue = 1337;
            fprintf(stderr, "myValue: %dn", this->myValue);
        }
        MyClass(int myFirstValue)
        {
            fprintf(stderr, "myValue: %dn", this->myValue);
        }
};
int main()
{
    /* Constructor is called */
    MyClass myInstance;
    /* Call other constructor ; myInstance->myValue is now trashed */
    myInstance = 100;
    return 0;
}

输出:

myValue: 1337
myValue: 1606416392

预期输出:

myValue: 1337
myValue: 1337

有没有办法保留初始化的成员变量?

当你这样做时

myInstance = 100;

使用构造函数MyClass(int)在 RHS 上构造临时MyClass。然后使用临时值为 LHS 分配值。

该构造函数不初始化成员变量。读取未初始化的成员会导致未定义的行为,在您的情况下,这似乎会导致打印垃圾值。

因此,您需要初始化它,假设您要将成员初始化为构造函数中传递的值:

MyClass(int myFirstValue) : myValue(myFirstValue)
{
  // as before
}

编辑,因为您希望成员的值1337,您需要

MyClass(int myFirstValue) : myValue(1337) { .... }
myInstance = 100;

是对函数MyClass& MyClass::operator=( MyClass const &other)的调用

但由于您没有实现它,因此调用了默认赋值运算符。如您所见,此函数将引用MyClass参数。这意味着必须将整数文字1 100转换为 MyClass 。C++实现可以自由地执行这样的隐藏的、用户定义的转换。在这种情况下,它做到了。由于您不初始化整数成员 MyClass(int myFirstValue)因此将进行默认初始化2。对于int变量,这意味着没有初始化和不确定的值。然后,尝试读取此未定义的值并将其分配给原始对象。这会导致未定义的行为,因此从现在开始,程序的行为是未定义的,非确定性的。

您可以将构造函数限制为仅使用 word explicit 显式调用,并解决此问题,初始化整数成员:

MyClass( int myFirstValue) : myValue( myFirstValue)
{
    //.... 
}

C++ 标准 n3337 § 12.3 转换

1) 类对象的类型转换可以由构造函数指定 以及通过转换功能。这些转换称为用户定义 转换,用于隐式类型转换(条款 4),用于 初始化 (8.5) 和显式类型转换 (5.4、5.2.9)。

2) 用户定义的转换仅在其所在位置应用 明确(10.2、12.3.2)。转换遵守访问控制规则 (第11条)。在解决歧义后应用访问控制 (3.4).

3) [ 注:有关在 函数调用以及下面的示例。— 尾注 ]

4) 最多一个用户定义的转换(构造函数或转换) 函数)隐式应用于单个值。

1 C++ 标准 n3337 § 2.14.2 文字 1) 整数文字是没有句点或指数部分的数字序列。整数文本可能具有指定其基数的前缀和指定其类型的后缀。序列的词法上的第一个数字数字是最重要的。十进制整数文本(以十为基数)以 0 以外的数字开头,并且由一系列十进制数字组成。八进制整数文本(以 8 为基数)以数字 0 开头,并且由一系列八进制数字组成。22 十六进制整数文本(以十六进制为基数)以 0x 或 0X 开头,并且由一系列十六进制数字组成,其中包括十进制数字和字母 A 到 F以及 A 到 F,十进制值为 10 到 15。[例:数字十二可以写成12,014,或0XC。— 结束示例 ]

2 C++ 标准 n3337 § 8.5 初始值设定项 6) 默认初始化类型 T 的对象意味着:— 如果 T 是(可能符合 cv 条件的)类类型(条款 9),则调用 T 的默认构造函数(和如果 T 没有可访问的默认构造函数,则初始化格式不正确);— 如果 T 是数组类型,则每个元素都是默认初始化的;— 否则,不执行初始化。如果程序调用 const 限定类型 T 的对象的默认初始化,则 T 应为类使用用户提供的默认构造函数键入。