I am new to namespaces and was trying this from C++ Primer
#include<iostream>
namespace Jill
{
double bucket;
double fetch;
struct Hill{ };
}
double fetch;
int main()
{
using namespace Jill;
Hill Thrill;
double water = bucket;
//double fetch; //<<<<<<<<<<<<//
std::cin>> fetch;
std::cin>> ::fetch;
std::cin>> Jill::fetch;
std::cout<<"fetch is "<<fetch;
std::cout<<"::fetch is "<< ::fetch;
std::cout<<"Jill::fetch is "<< Jill::fetch;
}
int foom()
{
Jill::Hill top;
Jill::Hill crest;
}
When the line marked //<<<<<<<<<<<<//
is not commented I get expected results. i.e. the
local
variable hides the global
and Jill::fetch
. But when I comment it out, there are 2 fetch left . global fetch
and Jill::fetch
. And the compiler gives the error
namespaceTrial1.cpp:17:13: error: reference to ‘fetch’ is ambiguous
namespaceTrial1.cpp:9:8: error: candidates are: double fetch
namespaceTrial1.cpp:5:9: error: double Jill::fetch
namespaceTrial1.cpp:20:26: error: reference to ‘fetch’ is ambiguous
namespaceTrial1.cpp:9:8: error: candidates are: double fetch
namespaceTrial1.cpp:5:9: error: double Jill::fetch
My question is why does the compiler get confused this lead to ambiguity? Why does it not assume fetch
as just Jill::fetch
, since I have added using namespace Jill
at the start of main()
If I use declarative using Jill::fetch;
at the start of main, the issue gets solved. because using Jill::fetch
makes it as if it has been declared at that location. So, its like there is a local fetch
variable. [Am i correct?] Why does using declaration
behave as if the variable was declared at that location and using directive
doesnt?
A Namespace Confusion attack is a type of software supply chain attack that tricks a package manager into downloading a malicious component instead of a proprietary one. To do this, bad actors upload a component with the same name as a proprietary component to an ecosystem with no namespace.
Nexus has a multi-tiered naming system that offers globally unique identification, personalization and branding opportunities. Three categories exist: local names, namespaces, and global names, all of which can be created via the Nexus desktop wallet.
When you declare a local variable shadowing a global/namespace variable, you explicitly tell the compiler about that. However, when you are using using
the variables of the namespace doesn't actually end up in the local scope.
From the specification (section 7.3.4, point 3):
A using-directive does not add any members to the declarative region in which it appears.
Also (from same section, point 6):
If name lookup finds a declaration for a name in two different namespaces, and the declarations do not declare the same entity and do not declare functions, the use of the name is ill-formed.
The using directive modifies name lookup in a way that isn't exactly intuitive to most programmers. The standard says this in [namespace.udir]p2:
During unqualified name lookup (3.4.1), the names appear as if they were declared in the nearest enclosing namespace which contains both the using-directive and the nominated namespace.
This wording means that names from the namespace do not appear in the current scope, but in some outer scope. In your example the using directive is in the function which is in the global namespace, and the Jill is also in the global namespace, so the names from Jill appears as if they are in the global namespace. (As Joachim said, the names aren't actually introduced there, so they don't immediately conflict with existing names and you only get ambiguous lookups when you actually use them.)
This is a simple case and the compiler gives you an error, which is good. It can actually get more complicated than that.
namespace Outer {
namespace Mid1 { int i = 1; }
namespace Mid2 {
namespace Tricky {
int i = 2;
namespace Inner {
void f() {
using namespace Mid1;
std::cout << i;
}
}
}
}
}
This will output 2, not 1, even though you had the using directive right next to the line referring to i. But the nearest enclosing namespace that contains both Mid1
and the using directive is Outer
, so Mid1::i
acts as if it was declared in Outer
. If you had an Outer::i
it would be shadowed by Tricky::i
, and Mid1::i
fares no better.
An easy solution is to ban using directives and only use using declarations and namespace aliases. They're far more intuitive.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With