How to understand the const variable between different block scopes - c++

I'm beginner in C++. I learned from the book "accelerated c++" about a const variable inside a block scope. It means that the "const variable will be destroyed when the scope ends at }.
But in the test: the const string variable s is defined inside the first block. In the second block, the s is also defined. When the second s is printed out the first block's s hasn't been destroyed.
I think the program is invalid, but the result is totally true when I compile the program. I don't known why it is. please help me to understand the code.
#include <iostream>
#include <string>
int main()
{
const std::string s = "a string";
std::cout << s << std::endl;
{
const std::string s = "another string";
std::cout << s << std::endl;
}
return 0;
}
the result is
a string
another string

Enlarge your program the following way
#include<iostream>
#include<string>
const std::string s = "a first string";
int main()
{
std::cout << s << std::endl;
const std::string s = "a string";
std::cout << s << std::endl;
{
const std::string s = "another string";
std::cout << s << std::endl;
}
std::cout << s << std::endl;
std::cout << ::s << std::endl;
return 0;
}
The program output is
a first string
a string
another string
a string
a first string
Each declaration in an internal scope hides a declaration in the outer scope with the same name (except function names that can be overloaded). But the variable declared in the outer scope is still alive. If a variable is declared within a namespace as the first variable s that is declared before main and belongs to the global namespace then you can use its qualified name to access the variable.
When an unqualified name is used then the compiler searches its declaration starting with the nearest scope.

Related

Accessing variables in an enclosing scope(not global) hidden by local declaration in C++?

The scope resolution operator :: can be used to access a global variable shadowed by a local declaration. How do you achieve the same for a variable declared in an enclosing scope but not global?
int main() {
int i = 10;
if (1) {
int i = 5;
std::cout << "Local i: " << i << std::endl;
std::cout << "Main's i: " << ?? << std::endl; //How to access main's i?
}
return 0;
}
I know this is bad practice. But I was just curious to know if this was possible. I reckon it's not.
An explanation of why it's not possible or how it is would be useful.
This is unfortunately not possible. Compiler warning options, like -Wshadow for GCC, can help avoiding such situations:
-Wshadow
Warn whenever a local variable or type declaration shadows another variable, parameter, type, class member (in C++), or instance
variable (in Objective-C) or whenever a built-in function is shadowed.
Note that in C++, the compiler warns if a local variable shadows an
explicit typedef, but not if it shadows a struct/class/enum. Same as
-Wshadow=global.
In your example, for instance, you'd get a warning like:
: In function 'int main()':
:7:9: error: declaration of 'i' shadows a previous local
[-Werror=shadow]
7 | int i = 5;
|
As #L. F. points out in a comment below, you can use references to still have access to the other i:
#include <iostream>
int main() {
int i = 10;
if (1) {
int& nonlocal_i = i; // just before shadowing
int i = 5;
std::cout << "Local i: " << i << std::endl;
std::cout << "Main's i: " << nonlocal_i << std::endl;
}
return 0;
}
But -Wshadow will still complain, and if you were going the extra mile to find an alternative name, you could just name the local i differently.
Note:
As user4581301 points out in a comment, code like int& i = i; doesn't do what you'd expect in an inner scope:
#include <iostream>
int main()
{
int i = 4;
{
int& i = i;
std::cout << i;
}
}
It tries to use the variable i to initialize itself. In Microsoft's compiler you get a compilation error like:
error C4700: uninitialized local variable 'i' used
In GCC, if you turn all the warnings on, you get this message:
error: reference 'i' is initialized with itself [-Werror=init-self]
But it silently compiles and does the wrong thing if you don't have the warnings turned on
You can access the outer variable by creating a reference to it prior to shadowing it:
int main()
{
int i = 10;
if (1)
{
int &main_i = i;
int i = 5;
std::cout << "Local i: " << i << std::endl;
std::cout << "Main's i: " << main_i << std::endl;
}
return 0;
}
No you can't use :: resolution operator for enclosing scopes. '::' operator can be used used as both unary and binary. You can use the unary scope operator if a namespace scope or global scope name is hidden by a particular declaration of an equivalent name during a block or class. For example -
#include <iostream>
using namespace std;
int tVar = 0;
int main(void) {
int tVar = 0;
::tVar = 5; // set global tVar to 5
tVar = 6; // set local tVar to 6
cout << ::tVar << ", " << tVar;
return 0;
}
and the binary use case of :: is what you've mentioned. Also to understand c++ blocks this article may help - http://www.ccplusplus.com/2011/08/scope-of-identifiers-in-c.html

Why is an "identifier" considered ambiguous with "identifier()" when they're used differently?

This is solely for example I happen to notice with!
I'm using cout with operator<< and why won't this program compile?
Why aren't they being considered the way function overloadings are?
#include <iostream> // imports the declaration of std::cout
using namespace std; // makes std::cout accessible as "cout"
int cout() // declares our own "cout" function
{
return 5;
}
int main()
{
cout << "Hello, world!"; // Compile error!
return 0;
}
At the point of the attempted stream insertion, there are two names cout in global scope: one from the standard library, std::cout, pulled into global scope by that infernal using declaration, and one defined as a function int cout(). In the expression
cout << "Hello, world!\n";
the use of cout is ambiguous. There is no function overloading for two reasons: first, std::cout is not a function, so would not take part in overloading. But more fundamentally, the use of cout in that expression is not a function call, so, again, there is no overloading. The name cout from the function definition is treated as a pointer to function, and the name cout from namespace std is the name of an object. There are two possible interpretations of that name, so its use in that << expression is ambiguous.

Why does my C++ code compile even with doubly declared variable?

I am trying to learn C++ from the book Accelerated C++. At the end of Chapter 1 there is an exercise that tripped me. Essentially, I am wondering why the following code compiles and runs perfectly:
#include <iostream>
#include <string>
int main() {
{
const std::string s = "a string";
std::cout << s << std::endl;
{
std::cout << s << std::endl;
const std::string s = "another string";
std::cout << s << std::endl;
};
}
return 0;
}
It seems to me that I am doubly declaring the string s, and from my understanding this is illegal. Could you help me understand this better? Thanks. The output this produces is:
a string
a string
another string
In C++, you are allowed to redeclare a variable in a nested scope. Within that scope, the redeclared variable takes precedence.
See [basic.scope.hiding] for a standard reference:
A name can be hidden by an explicit declaration of that same name in a nested declarative region or derived
class
These are two seperate variable because they are declared in a different scope. The scope of a variable is the 'area' of code in which it's visible.
The outer s is overwritten with s in inner body.

C++ Difference between inline anonymous instances and named instances

In a logging context, I would like to use a temporary instance of a utility class to collect some output, and use the destructor to dispose of the collected output. For example, printing to standard output as below.
I am noticing behavior differences depending whether the utility instance is constructed as an inline, anonymous instance as compared with a named automatic instance.
The named instances result in expected behavior and output. The inline instances have difficulty with the first insertion operation, apparently only working on operands which have simple conversions to int.
What is the difference between instances used in these different ways?
#include <string>
#include <sstream>
#include <iostream>
class Util
{
public:
std::ostringstream m_os;
Util() {}
~Util() { std::cout << m_os.str() << std::endl;}
};
int main (void)
{
// ----------- Using temporary anonymous instance -
// Output does not match expected, and the first insertion seems to
// only be able to handle instances that can be converted to int.
// Following prints "97key=val", but expect "akey=val"
(Util()).m_os << char('a') << std::string("key") << "=" << std::string("val");
// Following prints "0x80491eakey=val", but expect "Plain old C string key=val"
(Util()).m_os << "Plain old C string " << std::string("key") << "=" << std::string("val");
// Following results in syntax error
// error: no match for ‘operator<<’ in ‘Util().Util::m_os <<
(Util()).m_os << std::string("key") << "=" << std::string("val");
// ----------- Using named instance - output matches expected
// Block results in print "akey=val"
{
Util inst;
inst.m_os << char('a') << std::string("key") << "=" << std::string("val");
}
// Block results in print "Plain old C string key=val"
{
Util inst;
inst.m_os << "Plain old C string " << std::string("key") << "=" << std::string("val");
}
// Block results in print "key=val"
{
Util inst;
inst.m_os << std::string("key") << "=" << std::string("val");
}
return 0;
}
(Util()) creates a temporary object. As a result, (Util()).m_os is also a temporary object.
There are some definitions of operator<< as a member function, and some other definitions of it as a freestanding function. The former work on temporary objects, the latter does not, because a temporary cannot be bound to a reference-to-stream. Simplifying your code to a full example:
#include <stdio.h>
struct stream
{
stream& operator<<(int)
{ puts("operator<<(int)"); return *this; }
};
stream& operator<<(stream& s, char)
{ puts("operator<<(char)"); return s; }
struct streamwrapper
{
stream s;
};
int main()
{
streamwrapper w;
w.s << 'a'; // outputs operator<<(char)
streamwrapper().s << 'a'; // outputs operator<<(int)
}
Since the overloads you expected are unavailable, yet others are not, those other overloads get used instead of giving you a hard compiler error.

Modyfying temporary object

Can someone tell why test(2) object is destroyed after test_method() call?
#include<iostream>
#include<string>
using namespace std;
class test
{
int n;
public:
test(int n) : n(n)
{
cout << "test: " << n << endl;
}
~test()
{
cout << "~test: " << n << endl;
}
test & test_method()
{
cout << "test_method: " << n << endl;
return *this;
}
};
int main(int argc, const char *argv[])
{
cout << "main start" << endl;
const test &test1 = test(1);
const test &test2 = test(2).test_method();
cout << "main end" << endl;
}
Output is:
main start
test: 1
test: 2
test_method: 2
~test: 2
main end
~test: 1
test(2).test_method() returns a reference, which is bound to test2, and then the object to which it refers is destroyed at the end of the full expression, since it is a temporary object. That should not be a surprise.
The real surprise is that test1 remains a valid reference, because it is directly bound to a temporary, and binding a temporary to a reference extends the lifetime of the temporary to that of the reference variable.
You only have to note that in the test(2) case, the temporary object isn't bound to anything. It's just used to invoke some member function, and then its job is done. It doesn't "babysit" member functions, or in other words, lifetime extension isn't transitive through all possible future references.
Here's a simple thought experiment why it would be impossible to actually have "arbitrary lifetime extension":
extern T & get_ref(T &);
{
T const & x = get_ref(T());
// stuff
// Is x still valid?
}
We have no idea if x remains valid beyond the first line. get_ref could be doing anything. If it's implemented as T & get_ref(T & x) { return x; }, we might hope for magic, but it could also be this:
namespace { T global; }
T & get_ref(T & unused) { return global; }
It's impossible to decide within the original translation unit whether anything needs to be extended or not. So the way the standard has it at present is that it's an entirely trivial, local decision, just made when looking at the reference declaration expression, what the lifetime of the temporary object in question should be.
Because the C++ standard requires this behavior. Give the object a name if you want it to persist. It will persist as long as the name.
Edit: You your example, test1 is the name that you gave to the first object, whereas the second object has obtained no name at all, and so it does not outlast evaluation of the expression.