Accelerated C++ Solution to Exercise 1-5

Exercise 1-5

Part 1: Is this program valid? If so, what does it do? If not, say why not, and rewrite it to be valid.

#include <iostream>
#include <string>

int main()
{
    {
        std::string s = "a string";
        {
            std::string x = s + ", really";
            std::cout << s << std::endl;
        }
        std::cout << x << std::endl;
    }
    return 0;
}

Solution

No. The program is not valid and require correction.

Like the previous exercises (1-3 / 1-4), the key to this question is to understanding the term scope. One scope may not “see” what’s inside the other scope(s).

For clarity let me add some comments to the code to visualise these scopes.

// original program with comments added to visualise scope
#include <iostream>
#include <string>

int main()
{ // scope main starts

    { // scope main-1 starts

        std::string s = "a string";

        { // scope main-1-1 starts

            std::string x = s + ", really";
            std::cout << s << std::endl;

        } //scope main-1-1 ends

        std::cout << x << std::endl;

    } // scope main-1 ends

    return 0;

} // scope main ends

} // scope main ends
[/code]

Let me start off by stating the following facts (in general)

  • All local variables defined at the outer scope level may be seen/used by the inner scopes (at all levels).
  • The reverse is not possible however. i.e. All local variables defined at the inner scope level may NOT be seen/used by the outer scopes (at all levels), nor the scopes adjacent to it. (i.e. same level scopes).
  • i.e. the permeation of variables go from outer scope, to inner scope. It does not permeate to other scopes at the same level, and/or the inner scopes (at all levels).

To apply these facts to our case:

  • scope main-1-1 can see std::string variable s (which is defined in the outer scope main-1), and its own defined std::string variable x.
  • scope main-1 can see only its own defined variable std::string s. It cannot see the std::string variable x that lives at the inner scope main-1-1 level. Problem! Fail to perform that std::cout << x << std::endl step because it does not not what x is. from scope main-1 perspective the variable x is not declared.
  • scope main-1 has no idea of any variables defined in the inner scopes main-1 nor main-1-1. All it knows is that whenever the implementation hits the return statement, it is done.

To prove the point if we run the program as it is, we expect to see a compilation error

line (19): error: ‘x’ was not declared in this scope

To make the std::string x visible to the scope main-1, simply move the scope main-1-1 up 1 level by removing the curly braces. Like this:

// corrected - likely to work
#include <iostream>
#include <string>

int main()
{ // scope main starts

    { // scope main-1 starts

        std::string s = "a string";
        std::string x = s + ", really";
        std::cout << s << std::endl;
        std::cout << x << std::endl;

    } // scope main-1 ends

    return 0;

} // scope main ends

Running this corrected version program gives us the desirable result, as expected.

a string
a string, really

Process returned 0 (0x0)   execution time : 0.245 s
Press any key to continue.

Reference

Koenig, Andrew & Moo, Barbara E., Accelerated C++, Addison-Wesley, 2000

Accelerated C++ Solution to Exercise 1-4

Exercise 1-4

Part 1: Is the following program valid? if so what does it do? If not, why not?

Part 2: What if we add a semi-colon between the second-last and third-last (right) curly braces?

#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;
        }
    }

}

Solution (Part 1)

Yes. The program is valid.

Like the previous exercise (1-3), the key to this question is to understanding the term scope. Each pair of curly braces {} form a scope. It is okay to have scopes nested within a scope.

For clarity let me add some comments to the code to visualise these scopes.

#include <iostream>
#include <string>

int main()
{//scope main starts

    {   //scope main-1 start

        const std::string s = "a string";
        std::cout << s << std::endl;

        {   //scope main-1-1 starts

            const std::string s = "another string";
            std::cout << s << std::endl;

        }  //scope main-1-1 ends 

    }  //scope main-1 ends 

} //scope main ends

The const std::string variable s in scope main-1 is not the same const std::string variable s in scope main-1-1 (which is nested inside scope main-1). Even though scope main-1-1 is nested inside scope main-1, all local variables inside scope main-1-1 is hidden from view of main-1.

For completeness, let’s run the program at the top to confirm it runs okay.

a string
another string

Process returned 0 (0x0)   execution time : 0.317 s
Press any key to continue.

The program runs okay as expected.

Memory Treatment

Another thing to bear in mind is the fact that all local variables within a scope only has a life time within the scope. i.e. once the implementation reaches the closing curly brace, }, (in other words, the end of the scope) the local variables of that scope are destroyed. The memory that was taken up by the local variables are now freed up and returned back to the system.

In this case, we expect to see the followings memory allocations / de-allocations.

  • When scope main starts: memory allocated for any local variables of scope main (in this case, none).
  • When scope main-1 starts: memory allocated for the std::string s variable of scope main-1.
  • When scope main-1-1 starts: memory allocated for the std::string s variable of scope main-1-1.
  • When scope main-1-1 ends: The std::string s variable of scope main-1-1 is destroyed. Memory is freed up and returned to the system.
  • When scope main-1 ends: The std::string s variable of scope main-1 is destroyed. Memory is freed up and returned to the system.
  • When scope main ends: Any scope main local variables are destroyed (in this case none). Memory is freed up and returned to the system. (in this case none)

Notice how this differs to the case in exercise 1.3?

Solution (Part 2)

Adding a semi-colon (;) between the second last and third last right curly braces will still constitute a valid program. For clarity, this is what the program would look like with that semi-colon.

#include <iostream>
#include <string>

int main()
{//scope main starts

    {   //scope main-1 start

        const std::string s = "a string";
        std::cout << s << std::endl;

        {   //scope main-1-1 starts

            const std::string s = "another string";
            std::cout << s << std::endl;

        }  //scope main-1-1 ends 

        ;  // the additional semi-colon

    }  //scope main-1 ends 

} //scope main ends

The additional semi-colon essentially creates a null-statement within the main-1 scope. i.e. it has no effect to the code. I think the reason the authors ask this question is to solidify our understanding on scope. i.e. which scope does that semi-colon belong to? Writing a C++ code in the above manner helps us visualise this easier.

Submitting the program with this semi-colon would yield the same output.

Reference

Koenig, Andrew & Moo, Barbara E., Accelerated C++, Addison-Wesley, 2000