我有一个 C++/CLI 项目,它在 for 循环中声明了一个 String^ 变量,但没有对其进行初始化。在第一次迭代中,变量被设置为某个值。在随后的每个 迭代,它似乎保留了以前的值。每次循环时,局部作用域中的变量是否都不应初始化为 null(或等效值)? int 也会发生这种情况。另外,编译器 除非我将警告级别设置为 W4,否则不会警告可能未初始化的值,即使这样它也只会警告 int 而不是 String^。
这是显示行为的示例代码。
#include "stdafx.h"
using namespace System;
int main(array<System::String ^> ^args)
{
for(int n = 0; n < 10; n++)
{
String^ variable;
int x;
switch(n)
{
case 1:
variable = "One";
x = 1;
break;
case 5:
variable = "Five";
x = 5;
break;
}
Console::WriteLine("{0}{1}", variable, x);
}
}
这个的输出将是
One, 1
One, 1
One, 1
One, 1
Five, 5
Five, 5
Five, 5
Five, 5
Five, 5
我是否完全误解了应该如何初始化局部范围的变量?这是托管 C++ 独有的“功能”吗?如果我转换 这对于 C# 来说,编译器将对这两个变量发出警告,即使是在基本警告级别。
最佳答案
免责声明:我非常了解 C 和 C++; C++/CLI,没那么多。但是您看到的行为与我对 C 或 C++ 中的类似程序的预期基本相同。
String^
是 String
的句柄,类似于 C 或 C++ 中的指针。
除非 C++/CLI 添加新的句柄初始化规则,否则没有显式初始化的 String^
类型的 block 作用域变量最初将具有垃圾值,由其中发生的任何内容组成大块内存。
循环的每次迭代在概念上都会创建和销毁 {
和 }
之间定义的任何变量。并且每次迭代可能 都在相同的内存位置分配其局部变量(这不是必需的,但没有真正的理由不这样做)。编译器甚至可以生成在函数入口处分配内存的代码。
因此在循环的第一次迭代中,variable
被设置为 "One"
(或者更确切地说,设置为指向 "One"< 的句柄
),这是 Console::WriteLine
打印的值。没问题。
在第二次迭代中,variable
被分配到与第一次迭代相同的内存位置。没有为其分配新值,因此它保留了第一次迭代时存储在该内存位置的值。 x
也会发生同样的事情。
您不能指望保留以前的值,并且您的程序的行为是未定义的。如果您的目标是编写一个正确运行的程序,而不是了解这个错误程序的行为方式,那么解决方案是确保所有变量在使用前都已正确初始化。
如果您在第二次迭代而不是第一次迭代时进行初始赋值,程序可能会在第一次迭代时崩溃——尽管这并不能保证。
至于为什么编译器不警告这个,我不知道。我对提出编译器错误犹豫不决,但这可能是一个。
此外,即使启用了高警告级别,关于未初始化变量的警告也需要控制流分析,而这可能不会在默认情况下进行。启用警告 和 高级优化可能会为编译器提供足够的信息来警告 variable
和 x
。
它警告 x
而不是 W4
的 variable
似乎仍然很奇怪。
关于string - for 循环中的变量在每次迭代时都没有重新初始化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13883142/