在C ++中,何时可以在同一范围内看到两个同名变量?

时间:2020-12-14 16:50:06

This code illustrates something that I think should be treated as bad practice, and elicit warnings from a compiler about redefining or masking a variable:

这段代码说明了我认为应该被视为不良做法的内容,并引发编译器关于重新定义或屏蔽变量的警告:

#include <iostream>

int *a;

int* f()
{
  int *a = new int;
  return a;
}

int main()
{
  std::cout << a << std::endl << f() << std::endl;
  return 0;
}

Its output (compiled with g++):

它的输出(用g ++编译):

0
0x602010

I've looked at a couple references (Stroustrup and The Complete C++ Reference) and can't find anything about when and why this is allowed. I know that it's not within a single local scope, though.

我查看了几个引用(Stroustrup和完整的C ++参考),但无法找到关于何时以及为何允许这样做的任何内容。但我知道它不在一个局部范围内。

When and why is this allowed? Is there a good use for this construct? How can I get g++ to warn me about it? Do other compilers squawk about it?

何时以及为何允许这样做?这个结构有用吗?我怎样才能让g ++警告我呢?其他编译器是否会喋喋不休?

6 个解决方案

#1


It's allowed so that you can safely ignore global identifier overriding. Essentially, you only have to be concerned with global names you actually use.

这是允许的,这样您就可以安全地忽略全局标识符覆盖。从本质上讲,您只需要关注实际使用的全局名称。

Suppose, in your example, f() had been defined first. Then some other developer added the global declaration. By adding a name, f() which used to work, still works. If overriding was an error, then the function would suddenly stop working, even though it doesn't do anything at all with the newly added global variable.

假设,在您的示例中,首先定义了f()。然后其他一些开发者添加了全局声明。通过添加一个名称,f()曾经工作,仍然有效。如果覆盖是一个错误,那么该函数会突然停止工作,即使它对新添加的全局变量没有任何作用。

#2


As to why this is allowed: this is perfectly valid.

至于为什么允许这样做:这是完全有效的。

When you are within your f() function, you're defining a local scope. Local scopes override the global scope, so defining your "a" variable there "hides" the global int *a;

当你在f()函数中时,你正在定义一个局部范围。局部范围覆盖全局范围,因此定义“a”变量会“隐藏”全局int * a;

#3


This is perfectly valid, but I think that with -Wall you only get a warning when you shadow a parameter.

这是完全有效的,但我认为使用-Wall只会在影子参数时收到警告。

If you want warnings when you shadow any type of variable, You can use this, from the g++ manual page:

如果您想要隐藏任何类型的变量时发出警告,可以在g ++手册页中使用它:

   -Wshadow
       Warn whenever a local variable shadows another local variable, 
       parameter or global variable or whenever a built-in function is 
       shadowed.

Note that -Wshadow isn't included in -Wall by default.

请注意,默认情况下-Wshadow不包含在-Wall中。

#4


A lot of languages allow this sort of thing.
Usually (in relation to all languages) the most locally defined variable is the one you are referring too. Of the 20+ languages I have used this is very common.

许多语言允许这种事情。通常(与所有语言相关),最本地定义的变量也是您所指的变量。在我使用的20多种语言中,这是非常常见的。

Also most languages allow you to explicitly refer to the one in the outer scope.
For example C++ alows you to specify the variable in global scope with the :: operator.

此外,大多数语言允许您明确引用外部范围中的语言。例如,C ++允许您使用::运算符在全局范围内指定变量。

#include  <iostream>


int a = 5;
int main()
{
    int a = 6;

    std::cout << a << "\n" << ::a << "\n";
            // Local
                           // global
}

#5


To answer when this is allowed: basically in any two nested scopes.

要在允许的情况下回答:基本上在任何两个嵌套范围内。

For instance:

void foo() {
    int a;
    {
        int a;
    }
}

class Base {
    int a;
};
class Derived: public Base {
    int a; // Yes, the name Base::a is visible in the scope of Derived, even if private
};

class Foo() {
    int a;
    Foo(int a) : a(a) { } // Works OK
};

using std::swap;
void swap(MyClass& lhs, MyClass& rhs);
// Not strictly a variable, but name lookup in C++ happens before determining 
// what the name means.

Now, the answer must clearly be that having two 'things' with a single name in the same scope is generally allowed. This is possible because at most one of the names is actually defined in that scope; others would be merely visible in that scope. Name resolution rules determine which name is chosen, if there are multiple candidates.

现在,答案必须明确是通常允许在同一范围内使用单个名称的两个“事物”。这是可能的,因为至多其中一个名称实际上是在该范围内定义的;其他人只能在那个范围内看到。如果有多个候选者,名称解析规则将确定选择的名称。

You really do not want to give a warning for every case where the compiler picks between alternatives. That will give you tons of warnigns, on such innocent things as overloading and some smart template code.

您真的不想对编译器在备选方案之间选择的每种情况发出警告。这将为你提供大量的警告,如过载和一些智能模板代码等无辜的东西。

#6


As others have mentioned, this is perfectly legal, and is unambiguous to the compiler.

正如其他人所提到的,这是完全合法的,并且对编译器来说是明确的。

However, it's one of many features in programming languages which has the potential to cause confusion or hard-to-find bugs. Since it would be trivial to give different names to each of these variables, for the sake of clarity, I'd always suggest doing so.

但是,它是编程语言中的众多功能之一,可能会导致混淆或难以发现的错误。由于为每个变量赋予不同的名称是微不足道的,为了清楚起见,我总是建议这样做。

#1


It's allowed so that you can safely ignore global identifier overriding. Essentially, you only have to be concerned with global names you actually use.

这是允许的,这样您就可以安全地忽略全局标识符覆盖。从本质上讲,您只需要关注实际使用的全局名称。

Suppose, in your example, f() had been defined first. Then some other developer added the global declaration. By adding a name, f() which used to work, still works. If overriding was an error, then the function would suddenly stop working, even though it doesn't do anything at all with the newly added global variable.

假设,在您的示例中,首先定义了f()。然后其他一些开发者添加了全局声明。通过添加一个名称,f()曾经工作,仍然有效。如果覆盖是一个错误,那么该函数会突然停止工作,即使它对新添加的全局变量没有任何作用。

#2


As to why this is allowed: this is perfectly valid.

至于为什么允许这样做:这是完全有效的。

When you are within your f() function, you're defining a local scope. Local scopes override the global scope, so defining your "a" variable there "hides" the global int *a;

当你在f()函数中时,你正在定义一个局部范围。局部范围覆盖全局范围,因此定义“a”变量会“隐藏”全局int * a;

#3


This is perfectly valid, but I think that with -Wall you only get a warning when you shadow a parameter.

这是完全有效的,但我认为使用-Wall只会在影子参数时收到警告。

If you want warnings when you shadow any type of variable, You can use this, from the g++ manual page:

如果您想要隐藏任何类型的变量时发出警告,可以在g ++手册页中使用它:

   -Wshadow
       Warn whenever a local variable shadows another local variable, 
       parameter or global variable or whenever a built-in function is 
       shadowed.

Note that -Wshadow isn't included in -Wall by default.

请注意,默认情况下-Wshadow不包含在-Wall中。

#4


A lot of languages allow this sort of thing.
Usually (in relation to all languages) the most locally defined variable is the one you are referring too. Of the 20+ languages I have used this is very common.

许多语言允许这种事情。通常(与所有语言相关),最本地定义的变量也是您所指的变量。在我使用的20多种语言中,这是非常常见的。

Also most languages allow you to explicitly refer to the one in the outer scope.
For example C++ alows you to specify the variable in global scope with the :: operator.

此外,大多数语言允许您明确引用外部范围中的语言。例如,C ++允许您使用::运算符在全局范围内指定变量。

#include  <iostream>


int a = 5;
int main()
{
    int a = 6;

    std::cout << a << "\n" << ::a << "\n";
            // Local
                           // global
}

#5


To answer when this is allowed: basically in any two nested scopes.

要在允许的情况下回答:基本上在任何两个嵌套范围内。

For instance:

void foo() {
    int a;
    {
        int a;
    }
}

class Base {
    int a;
};
class Derived: public Base {
    int a; // Yes, the name Base::a is visible in the scope of Derived, even if private
};

class Foo() {
    int a;
    Foo(int a) : a(a) { } // Works OK
};

using std::swap;
void swap(MyClass& lhs, MyClass& rhs);
// Not strictly a variable, but name lookup in C++ happens before determining 
// what the name means.

Now, the answer must clearly be that having two 'things' with a single name in the same scope is generally allowed. This is possible because at most one of the names is actually defined in that scope; others would be merely visible in that scope. Name resolution rules determine which name is chosen, if there are multiple candidates.

现在,答案必须明确是通常允许在同一范围内使用单个名称的两个“事物”。这是可能的,因为至多其中一个名称实际上是在该范围内定义的;其他人只能在那个范围内看到。如果有多个候选者,名称解析规则将确定选择的名称。

You really do not want to give a warning for every case where the compiler picks between alternatives. That will give you tons of warnigns, on such innocent things as overloading and some smart template code.

您真的不想对编译器在备选方案之间选择的每种情况发出警告。这将为你提供大量的警告,如过载和一些智能模板代码等无辜的东西。

#6


As others have mentioned, this is perfectly legal, and is unambiguous to the compiler.

正如其他人所提到的,这是完全合法的,并且对编译器来说是明确的。

However, it's one of many features in programming languages which has the potential to cause confusion or hard-to-find bugs. Since it would be trivial to give different names to each of these variables, for the sake of clarity, I'd always suggest doing so.

但是,它是编程语言中的众多功能之一,可能会导致混淆或难以发现的错误。由于为每个变量赋予不同的名称是微不足道的,为了清楚起见,我总是建议这样做。