构造函数销毁成员变量
Constructor destroys member variables
为什么第二次调用构造函数时初始化的成员变量被删除?
示例:
class MyClass {
private:
unsigned myValue;
public:
MyClass(void)
{
this->myValue = 1337;
fprintf(stderr, "myValue: %d\n", this->myValue);
}
MyClass(int myFirstValue)
{
fprintf(stderr, "myValue: %d\n", 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)
但因为您没有实现它,所以调用了 default 赋值运算符。如您所见,此函数将 MyClass
引用作为参数。这意味着整数文字 1 100
必须转换为 MyClass
。 C++ 实现可以自由地进行这样的隐藏、用户定义 转换。它在这种情况下做到了。因为您没有在 MyClass(int myFirstValue)
中初始化整数成员,所以 默认初始化 2 发生了。对于 int
变量,这意味着没有初始化和 未确定的 值。然后您尝试读取并将此未定义的值分配给您的原始对象。这会导致未定义的行为,因此从现在开始,您的程序的行为是未定义的、不确定的。
您可以限制构造函数仅使用单词 explicit
显式调用并解决初始化整数成员的问题:
MyClass( int myFirstValue) : myValue( myFirstValue)
{
//....
}
C++ 标准 n3337 § 12.3 转换
1) Type conversions of class objects can be specified by constructors
and by conversion functions. These conversions are called user-defined
conversions and are used for implicit type conversions (Clause 4), for
initialization (8.5), and for explicit type conversions (5.4, 5.2.9).
2) User-defined conversions are applied only where they are
unambiguous (10.2, 12.3.2). Conversions obey the access control rules
(Clause 11). Access control is applied after ambiguity resolution
(3.4).
3) [ Note: See 13.3 for a discussion of the use of conversions in
function calls as well as examples below. — end note ]
4) At most one user-defined conversion (constructor or conversion
function) is implicitly applied to a single value.
1 C++ 标准 n3337 § 2.14.2 文字 1) 整数文字是没有句点或指数部分的数字序列。整数文字可能有
指定其基数的前缀和指定其类型的后缀。序列的词法第一个数字
的数字是最重要的。十进制整数文字(以十为基数)以 0 以外的数字开头,并且
由一系列十进制数字组成。八进制整数文字(以八为基数)以数字 0 开头,
由一系列八进制数字组成。22 十六进制整数文字(基数为十六)以 0x 或 0X 开头,
由一系列十六进制数字组成,其中包括十进制数字和字母 a 到 f
以及 A 到 F,十进制值为 10 到 15。 [ 例子:数字十二可以写成 12,
014 或 0XC。 — 结束示例]
2 C++ 标准 n3337 § 8.5 初始化器 6) 默认初始化类型 T 的对象意味着:
— 如果 T 是(可能是 cv 限定的)class 类型(第 9 条),则调用 T 的默认构造函数(并且
如果 T 没有可访问的默认构造函数,则初始化格式错误);
— 如果 T 是数组类型,则每个元素都是默认初始化的;
— 否则,不执行初始化。
如果程序要求默认初始化 const 限定类型 T 的对象,则 T 应为 class
使用用户提供的默认构造函数键入。
为什么第二次调用构造函数时初始化的成员变量被删除?
示例:
class MyClass {
private:
unsigned myValue;
public:
MyClass(void)
{
this->myValue = 1337;
fprintf(stderr, "myValue: %d\n", this->myValue);
}
MyClass(int myFirstValue)
{
fprintf(stderr, "myValue: %d\n", 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)
但因为您没有实现它,所以调用了 default 赋值运算符。如您所见,此函数将 MyClass
引用作为参数。这意味着整数文字 1 100
必须转换为 MyClass
。 C++ 实现可以自由地进行这样的隐藏、用户定义 转换。它在这种情况下做到了。因为您没有在 MyClass(int myFirstValue)
中初始化整数成员,所以 默认初始化 2 发生了。对于 int
变量,这意味着没有初始化和 未确定的 值。然后您尝试读取并将此未定义的值分配给您的原始对象。这会导致未定义的行为,因此从现在开始,您的程序的行为是未定义的、不确定的。
您可以限制构造函数仅使用单词 explicit
显式调用并解决初始化整数成员的问题:
MyClass( int myFirstValue) : myValue( myFirstValue)
{
//....
}
C++ 标准 n3337 § 12.3 转换
1) Type conversions of class objects can be specified by constructors and by conversion functions. These conversions are called user-defined conversions and are used for implicit type conversions (Clause 4), for initialization (8.5), and for explicit type conversions (5.4, 5.2.9).
2) User-defined conversions are applied only where they are unambiguous (10.2, 12.3.2). Conversions obey the access control rules (Clause 11). Access control is applied after ambiguity resolution (3.4).
3) [ Note: See 13.3 for a discussion of the use of conversions in function calls as well as examples below. — end note ]
4) At most one user-defined conversion (constructor or conversion function) is implicitly applied to a single value.
1 C++ 标准 n3337 § 2.14.2 文字 1) 整数文字是没有句点或指数部分的数字序列。整数文字可能有 指定其基数的前缀和指定其类型的后缀。序列的词法第一个数字 的数字是最重要的。十进制整数文字(以十为基数)以 0 以外的数字开头,并且 由一系列十进制数字组成。八进制整数文字(以八为基数)以数字 0 开头, 由一系列八进制数字组成。22 十六进制整数文字(基数为十六)以 0x 或 0X 开头, 由一系列十六进制数字组成,其中包括十进制数字和字母 a 到 f 以及 A 到 F,十进制值为 10 到 15。 [ 例子:数字十二可以写成 12, 014 或 0XC。 — 结束示例]
2 C++ 标准 n3337 § 8.5 初始化器 6) 默认初始化类型 T 的对象意味着: — 如果 T 是(可能是 cv 限定的)class 类型(第 9 条),则调用 T 的默认构造函数(并且 如果 T 没有可访问的默认构造函数,则初始化格式错误); — 如果 T 是数组类型,则每个元素都是默认初始化的; — 否则,不执行初始化。 如果程序要求默认初始化 const 限定类型 T 的对象,则 T 应为 class 使用用户提供的默认构造函数键入。