你将两个相关但不同的概念混在一起,因此你感到困惑。但这不是你的错,因为大多数关于这个问题的教学材料不一定能清楚地阐明这两个概念之间的区别。
变量范围:这是源代码中符号(变量)可见的区域。
对象生命周期:这是程序运行时对象存在的时间。
这给我们带来了需要理解和区分的其他两个概念:
-
一个变量是一个编译时概念:它是引用对象的名称(符号)
-
一个东西是运行时的“实体”,是类型的实例。
让我们回到你的例子:
int main()
{
int x{};
int x{};
}
在这里,您尝试在同一范围内声明 2 个不同的变量。这两个变量在函数作用域内具有相同的名称,因此当您“说出”名称时x
(当你写下符号x
)你不知道你会引用哪个变量。所以这是不允许的。
int main()
{
while(true)
{
int x{};
}
}
在这里,您在 while 主体范围内声明了一个变量。当你写的时候x
在此范围内,您引用此变量。没有歧义。没问题。有效代码。请注意,有关声明和变量范围的讨论适用于编译时,即我们正在讨论您编写的代码的含义。
然而,当我们讨论对象生命周期时,我们谈论的是运行时,即编译的二进制文件运行的那一刻。是的,在运行时,会连续创建和销毁多个对象。所有这些对象都由符号引用x
在 while 主体范围内。但这些对象的生命周期不要重叠。 IE。当您运行程序时,将创建第一个对象。在源代码中它被命名为x
在 while-body 范围内。然后该对象被销毁,重新进入循环并创建一个新对象。它也被命名为x
在 while-body 范围内的源代码中。然后销毁,重新进入while,创建一个新对象等等。
为了让您对此事有更广泛的了解,请考虑您可以:
从未引用对象的变量
{ // not global scope
int a; // <-- not initialized
}
变量a
未初始化,因此永远不会在运行时创建对象。
没有名称的对象:
int get_int();
{
int sum = get_int() + get_int();
}
两次调用该函数返回两个对象get_int()
。这些对象是临时的。他们从未被命名。
在变量范围内实例化多个对象。
这是一个高级的、人为的示例,位于 C++ 的边缘。只是表明这在技术上是可行的:
{
int x;
// no object
new (&x) int{11}; // <-- 1st object created. It is is named `x`. Start of its lifetime
// 1st object is alive. Named x
x.~int(); // <-- 1st object destructed. End of its lifetime
// no object
new (&x) int{24}; // <-- 2nd object created. Also named `x`
// 2nd object alive. Named x
} // <-- implicit end of the lifetime of 2nd object.
范围x
是由大括号分隔的整个块。然而,在此范围内有两个具有不同的非重叠生命周期的对象。