The design and evolution of C++

Hi,
This is the paragraph from "Design and evolution of C++" by Bjarne Stroustrup. First let me tell you that this is a wonderful book.

Can
"Several key decisions in the design of c++
The representation of objects of the user-defined type is part of the class decleration. This has far reaching implications. For example, it means that true local variables of a user-defined data type can be implemented without the use of free store (also called heap store and dynamic store) or garbage collection. It also means that a function must be recompiled if the representation of an object it uses directly is changed. . C++ facilitates interfaces that avod such recompilaton."

I did not understand the underlined sentence.
May be this question is too basic and I am missing something. I would be really thankful if someone takes time and explaining the meaning of this.

Thanks,
Johnny
Computers store programs in several different chunks of memory.

Data

There is the "data" block, where all constant values are stored. For example, in
1
2
  string s = "Hello world!";

the ASCIIZ character sequence "Hello world!" is stored in the data segment.

Text

There is the "text" or "code" block, where the code that makes things happen is stored. For example:
1
2
3
4
5
  int main()
    {
    cout << "Hello world!\n";
    return 0;
    }

Everything that does something -- computer instructions -- is put in the text block. (Remember that the character string goes in the data block.)

Stack

There is the "stack", which is used for temporary variables and information about where to return to when a function terminates, etc. The stack is so called because it is a LIFO structure.
1
2
3
4
5
6
7
  template <typename ValueType>
  void swap( ValueType& a, ValueType& b )
    {
    ValueType c = a;
    a = b;
    b = c;
    }

In this example, the variables a, b, and c are all stored on the stack. (Remember that a reference is a pointer in disguise, so a and b are actually pointers to ValueType, but c is actually a full-blown instance of ValueType.)

when the function returns, it calls c's destructor, goes back to from where the function was called, and restores the stack to its previous state.

Heap

Finally, there is the "heap", which is free (or unused) space that the program can use for dynamic memory allocations.
 
  int* numbers = new int[ 100 ];

Remember, if numbers is in a function, it is stored on the stack. But the integers it points to are all stored somewhere in the heap. new and delete (and malloc() and free()) manage the parceling of the heap.


So, what does it all mean?

Typically, a language will use the heap to allocate memory for class type objects.

This has the advantage that code that uses the object only needs to worry about its local pointer (or reference) to that object. For example, in Delphi Pascal, an object is created thus:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
type
  tGreeting = class
    public
      procedure say_hello;
    end;

procedure tGreeting.say_hello;
  begin
  writeln( 'Hello world!' )
  end;

var greet: tGreeting;
begin
  new( greet );     // create a tGreeting on the heap and assign its address to 'greet'
  greet.say_hello;  // use the object's methods
  dispose( greet )  // destroy the object and return its memory back to the heap
end.

The variable greet is just a pointer (or "reference") to the object, and all the stack space that is needed for it is the size of a pointer.

The disadvantage is that you must always explicitly new and dispose every object you use.

C++, however, has the friendly feature that you can create and treat an object as if it were a local variable: on the stack and completely ignoring the heap. (The object may use the heap, but the object itself is stored on the stack.) This means that you can do things like create local, nameless objects:
1
2
3
4
5
6
void foo( string& s ) { cout << s; }
int main()
  {
  foo( string( "Hello world!" ) );
  return 0;
  }

The string passed to foo() as argument only exists on the stack, and it is automatically destroyed when after foo() is done with it.

The disadvantage is that now the code that creates the local object needs to know how much space the object uses on the stack, where local variables are kept. Meaning that if you change the object's size the function that uses it must be recompiled to accommodate the new size.

Whew. Hope this helps.
Last edited on
Thanks for the wonderful explanation. Now I understood the concept. I tried to write an example to understand more..

But I am unbale to create a function, where Object size can be changed during run time and getting some sort of error..

Can you please suggest me an example for that.

Thanks,
Johnny
To add more, I tried the following example,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// LocalObjects.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <string.h>


class Greeting
{
private:
	int date;
	int month;
	int year;
public:

	//Default constructor
    Greeting()
	{
		date=01;
		month=01;
		year=1970;
	}

	//Constructor 1
	Greeting(int Date,int Month, int Year)
	{
		date=Date;
		month=Month;
		year=Year;
	}

	void PrintDate()
	{
		std::cout<<date<<" "<<month<<" "<<year<<std::endl;
	}
};

void PrintOnce(Greeting& greet);
void PrintTwice(Greeting& greet1,Greeting& greet2);

int _tmain(int argc, _TCHAR* argv[])
{
	char ch;
	std::cin>>ch;
	while(ch!='x')
	{
	if(ch=='1')
	{
		PrintOnce(Greeting(12,31,2008));
	}
	else
		PrintTwice(Greeting(12,20,2008),Greeting());

	std::cin>>ch;
	}
	return 0;
}

//One object is created on stack
void PrintOnce(Greeting& greet)
{
	greet.PrintDate();
}

//Two objects are created on stack
void PrintTwice(Greeting& greet1,Greeting& greet2)
{
	greet1.PrintDate();
	greet2.PrintDate();
}



Here PrintOnce will create one Greeting object on stack and PrintTwice will create two Greeting objects on Stack. and the function will be decided based on users input at runtime.
The program worked, eventhough the size of objects ( I mean 1*sizeOfGreeting or 2* sizeOfGreeting)..
but I think it is not a valid example since I am using different functions, and the size of stack space created by a particular function is Constant

Unable to think of any function where size of object can be varied.

Thanks,
Johnny
Last edited on
You can't. The C++ compiler takes care of all that stuff for you, and makes sure that the functions properly handle their local variables.

The original comment is really just for geeks, because it doesn't really mean much. If you change a header file, every module that uses it gets recompiled anyway...
It also means that a function must be recompiled if the representation of an object it uses directly is changed. . C++ facilitates interfaces that avod such recompilaton."


I dunno.. i kinda read that sentance differently..

what I think that's talking about, is if you change how something is stored..

I tend to use a lot of hiding in my programming.. If i make an object that holds data, I put that data in the private section, then make an interface in the public section to give limited access to that data. e.g.:

1
2
3
4
5
6
7
8
9
10
class myobject
{
   public:
      int get_id()
      {
         return myid; // this returns the value of myid
      }
   private:
      int myid; // and this is the variable
};


What this does, is make it so that programmers using my object can get the value but cannot change it. I would make another public function to control how it would be changed so that they can't break it accidently.

However, now people are using my object, expecting an int, and I later decide to change it to a char internally (it only needs to hold up to 255 anyway). So I change my interface so that it converts from char to int or vice versa so that it never breaks their code.

This is the purpose to interfaces.. and prevent them from having to re-do thier functions that work with my object, because from their point of view, nothing changed. Even though from my objects point of view, it uses less memory or is more efficient.

This is how I read those sentances, anyway. Am I wrong?
@Duoas:

A typo; stack works on LIFO (last in first out) basis, not FIFO.

Example, recursion.
Oops. I'll edit it above.
Aakanaar: Duoas is referring to the compilation process. When you compile a project with multiple source files the compiler will link then. When you recompile it will usually only re-compile the object files that have changed, and those that reference the changed ones. This is what Duoas was talking about.

What you are explaining is encapsulation, and has nothing to do with function re-compilation at all. Only code compliance and compatibility. Plus, Encapsulation should be used by most C++ programmers as it's one of the 3 fundamental OO rules.
ok.. thanks for clearing that up for me. and yes, I've worked with php and other languages that wern't specifically OO before, but once I started working with C++ (and doing some OO with php which is capable of it as of late) i've grown fond of encapsulation..

It really goes a long way towards splitting a very large program up into managable bites.
OO is one of a few good development methodologies. It's surely not the only one (AOP for example). But I am a big fan of OO and Agile.

OO is not just splitting up the code. OO lets you implement a ot of reusable patterns easily to solve known problems (google Design Patterns). The code is also immensely powerful when using polymorphisms to store and work with data objects in a parent-child hierarchy.
Topic archived. No new replies allowed.