1 Becoming More Effective with C++ … Day Two Stanley B. Lippman

Slides:



Advertisements
Similar presentations
Pointers Typedef Pointer Arithmetic Pointers and Arrays.
Advertisements

Abstract Data Types Data abstraction, or abstract data types, is a programming methodology where one defines not only the data structure to be used, but.
Pointers Revisited l What is variable address, name, value? l What is a pointer? l How is a pointer declared? l What is address-of (reference) and dereference.
1 Pointers A pointer variable holds an address We may add or subtract an integer to get a different address. Adding an integer k to a pointer p with base.
A RRAYS, P OINTERS AND R EFERENCES 1. A RRAYS OF O BJECTS Arrays of objects of class can be declared just like other variables. class A{ … }; A ob[4];
6/10/2015C++ for Java Programmers1 Pointers and References Timothy Budd.
Chapter 10.
Chapter 14: Overloading and Templates
VBA Modules, Functions, Variables, and Constants
Rossella Lau Lecture 8, DCO10105, Semester B, DCO10105 Object-Oriented Programming and Design  Lecture 8: Polymorphism & C++ pointer  Inheritance.
 2006 Pearson Education, Inc. All rights reserved Midterm review Introduction to Classes and Objects.
Classes: A Deeper Look Systems Programming.
OOP Spring 2006 – Recitation 31 Object Oriented Programming Spring 2006 Recitation 3.
Shallow Versus Deep Copy and Pointers Shallow copy: when two or more pointers of the same types point to the same memory – They point to the same data.
Review of C++ Programming Part II Sheng-Fang Huang.
OOP Languages: Java vs C++
Programming Languages and Paradigms Object-Oriented Programming.
 2006 Pearson Education, Inc. All rights reserved Classes: A Deeper Look.
You gotta be cool. Access Functions and Utility Functions Preprocessor Wrapper Looking Ahead to Composition and Inheritance Object Size Class Scope and.
Pointer Data Type and Pointer Variables
Operator Precedence First the contents of all parentheses are evaluated beginning with the innermost set of parenthesis. Second all multiplications, divisions,
The Rest of the Story.  Constructors  Compiler-generated  The Initializer List  Copy Constructors  Single-arg (conversion ctors)  The Assignment.
Nirmalya Roy School of Electrical Engineering and Computer Science Washington State University Cpt S 122 – Data Structures Classes: A Deeper Look Part.
CS212: Object Oriented Analysis and Design Lecture 6: Friends, Constructor and destructors.
Object Oriented Programming with C++/ Session 6 / 1 of 44 Multiple Inheritance and Polymorphism Session 6.
Copyright  Hannu Laine C++-programming Part 3 Hannu Laine.
 2006 Pearson Education, Inc. All rights reserved Classes: A Deeper Look, Part 2.
 2006 Pearson Education, Inc. All rights reserved Operator Overloading; String and Array Objects.
Defining New Types Lecture 21 Hartmut Kaiser
CPS120: Introduction to Computer Science Functions.
C++ Memory Overview 4 major memory segments Key differences from Java
Pointers and Dynamic Memory Allocation Copyright Kip Irvine 2003, all rights reserved. Revised 10/28/2003.
Object-Oriented Programming in C++
Concordia TAV 2002 Comp5421_421 Comp5421 Object Oriented Programming Using C++ Efficiently Lecture 4 (2) Tianxiang Shen Summer 2002 Department of Computer.
Chapter 12: Pointers, Classes, Virtual Functions, and Abstract Classes.
CPSC 252 Operator Overloading and Convert Constructors Page 1 Operator overloading We would like to assign an element to a vector or retrieve an element.
Copyright 2005, The Ohio State University 1 Pointers, Dynamic Data, and Reference Types Review on Pointers Reference Variables Dynamic Memory Allocation.
Visual C# 2012 for Programmers © by Pearson Education, Inc. All Rights Reserved.
CS 376b Introduction to Computer Vision 01 / 23 / 2008 Instructor: Michael Eckmann.
C Functions Three major differences between C and Java functions: –Functions are stand-alone entities, not part of objects they can be defined in a file.
CPS4200 Unix Systems Programming Chapter 2. Programs, Processes and Threads A program is a prepared sequence of instructions to accomplish a defined task.
Lecture 3 Classes, Structs, Enums Passing by reference and value Arrays.
CPSC 252 The Big Three Page 1 The “Big Three” Every class that has data members pointing to dynamically allocated memory must implement these three methods:
Chapter 10: Classes and Data Abstraction. Objectives In this chapter, you will: Learn about classes Learn about private, protected, and public members.
C++ Programming: From Problem Analysis to Program Design, Third Edition Chapter 15: Overloading and Templates.
Functions Illustration of: Pass by value, reference Scope Allocation Reference: See your CS115/215 textbook.
1 MORE ON MODULAR DESIGN: MODULE COMMUNICATIONS. 2 WHEN A FUNCTION IS INVOKED, MEMORY IS ALLOCATED LOCALLY FOR THE FORMAL PARAMETERS AND THE VALUE OF.
1 Classes II Chapter 7 2 Introduction Continued study of –classes –data abstraction Prepare for operator overloading in next chapter Work with strings.
Engineering Classes. Objectives At the conclusion of this lesson, students should be able to: Explain why it is important to correctly manage dynamically.
Chapter 10: Classes and Data Abstraction. Classes Object-oriented design (OOD): a problem solving methodology Objects: components of a solution Class:
Struct s (7.4) Used as data aggregates for an entity can be different types of data e.g. for student id, name, GPA, address,... Similar to classes, but.
Extra Recitations Wednesday 19:40-22:30 FENS L055 (tomorrow!) Friday 13:40-16:30 FENS L063 Friday 17: :30 FENS L045 Friday 19:40-22:30 FENS G032.
1 Recall that... char str [ 8 ]; str is the base address of the array. We say str is a pointer because its value is an address. It is a pointer constant.
1 Chapter 15-1 Pointers, Dynamic Data, and Reference Types Dale/Weems.
Recap Introduction to Inheritance Inheritance in C++ IS-A Relationship Polymorphism in Inheritance Classes in Inheritance Visibility Rules Constructor.
Dynamic Memory Management & Static Class Members Lecture No 7 Object Oriented Programming COMSATS Institute of Information Technology.
Pointers and Arrays Dynamic Variables and Arrays.
Prof. Amr Goneid, AUC1 CSCE 210 Data Structures and Algorithms Prof. Amr Goneid AUC Part R2. Elementary Data Structures.
DYNAMIC MEMORY ALLOCATION. Disadvantages of ARRAYS MEMORY ALLOCATION OF ARRAY IS STATIC: Less resource utilization. For example: If the maximum elements.
Memory Management.
Eine By: Avinash Reddy 09/29/2016.
Overview 4 major memory segments Key differences from Java stack
Friend Class Friend Class A friend class can access private and protected members of other class in which it is declared as friend. It is sometimes useful.
Motivation and Overview
Java Primer 1: Types, Classes and Operators
Pointers Revisited What is variable address, name, value?
Overview 4 major memory segments Key differences from Java stack
Chapter 15 Pointers, Dynamic Data, and Reference Types
9-10 Classes: A Deeper Look.
9-10 Classes: A Deeper Look.
Presentation transcript:

1 Becoming More Effective with C++ … Day Two Stanley B. Lippman

2 The Problem of Static Initialization

3 Complex Global Objects Global objects are problematic for many reasons. Their primary benefit is that they simplify information sharing across functions, modules, and libraries. The three primary drawbacks of global objects are The direct use of global objects across functions, modules, and/or libraries results in code that is difficult to reuse or modify in any significant way. In a threaded environment, global objects require locks before write access. Complex global objects are considerably more expensive to initialize, and are difficult to program correctly. In this unit, we look at this last issue, that of complex global objects.

4 C-Style strings vs. string Class First, we need to understand what it means to say that a global object is complex. Consider the following pairs of global declarations. In this pair, the first instance is a C-style string. The second is a standard library string object. Both hold a constant string literal indicating a version number. What are the differences in initialization? const char* const version1 = “0.00 ”; const string version2( “0.00 ” );

5 C-Style strings vs. string Class The first instance represents a constant expression. version1 can be completely evaluated at compile-time. Typically, the string literal is allocated in the program data segment. (Alternatively, the implementation may use a string table to avoid multiple instances of the same string literal.) version1 is initialized to the location of the string literal during compilation. There is no run-time overhead. const char* const version1 = “0.00 ”;

6 C-Style strings vs. string Class The second instance represents a constructor invocation. This in general cannot be evaluated at compile-time. The string literal is still allocated during compilation. The actual invocation of the string constructor, however, must be delayed until program start-up. In addition, if version2 is needed by another global object not defined in the same file, we have a potentially serious dependency problem. (More on that later.) const string version2( “0.00 ” );

7 Built-in Array vs. vector Class In this pair, the first instance is a built-in array. The second is a standard library vector object. Both are initialized to the same four constant expressions. What are the differences in initialization? int lut1[] = { 7, 12, 48, 106 }; vector lut2( lut1, lut1+4 );

8 Built-in Array vs. vector Class In this pair, the first instance is a built-in array object. The second is a standard library vector object. Both are initialized to the same values. Again, the first instance represents a constant expression. lut1 can be completely evaluated at compile-time. Typically, the array memory is allocated in the program data segment with the elements initialized to the literal values. There is no run-time overhead. (Of course, only constant expressions can be used within the initialization list.) int lut1[] = { 7, 12, 48, 106 };

9 Built-in Array vs. vector Class The second instance again represents a run-time constructor invocation. The begin and end address marking off the range of elements with which to initialize lut2 are constant expressions. The iteration across that range to copy the values is a run-time activity. Again, if lut2 is needed by another global object not defined in the same file, we have the same potentially serious dependency problem. vector lut2( lut1, lut1+4 );

10 Pointer Initializations In this pair, both are pointers to objects of type int. Both address an integer object containing the value 7. One is initialized to the address of the first element of lut1. The other is initialized with a copy of that element’s value. The object it addresses is allocated on the heap. What are the differences in initialization? int lut1[] = { 7, 12, 48, 106 }; int *pi1 = &lut1[ 0 ]; int *pi2 = new int( lut1[ 0 ] );

11 Pointer Initializations In this pair, the first instance is initialized with the address of the first array element. The address of an object is a constant expression: the compiler knows its value. The memory for the pointer is allocated within the data segment by the compiler and initialized with the address of the first element during code generation. There is no run-time overhead. int lut1[] = { 7, 12, 48, 106 }; int *pi1 = &lut1[ 0 ];

12 Pointer Initializations In this pair, the second instance invokes the new expression. The new expression is actually a library call. It cannot be evaluated at compile-time. Heap memory, in general, is a run-time resource that requires one or two function calls. So, although this does not involve a class constructor, it still requires a run-time function invocation. int lut1[] = { 7, 12, 48, 106 }; int *pi2 = new int( lut1[ 0 ] );

13 Simple Type Initialization In this pair, both objects are the built-in integer data type. What are the differences in initialization? Or, rather, at this point, why is the second instance a run-time initialization? int ival1 = 7; int ival2 = lut1[ 0 ];

14 Simple Type Initialization The first instance is initialized to a constant literal. The compiler is able to completely evaluate the expression and complete the initialization during code-generation. The second instance is initialized to the value of a non-constant integer object. The value associated with a non-const object of any type cannot be known until run-time. While no constructor or function needs to be invoked in the initialization of ival2, it still cannot be initialized at compile-time and requires static initialization. int ival1 = 7; int ival2 = lut1[ 0 ];

15 Summy: Constant Expressions Each pair’s first definition makes use of constant expressions, and result in compile-time initialization that is loaded within the program’s data segment: const char* const version1 = “0.00 ”; int lut1[] = { 7, 12, 48, 106 }; int *pi1 = &lut1[ 0 ]; int ival1 = 7; A constant expression is an expression that can be fully evaluated at compile-time. Yes, the address of an object is a constant expression! In the C language, global data can only be initialized with constant expressions …

16 Summy: Constant Expressions Each pair’s second definition requires run-time evaluation of its initial value. Evaluation must be delayed until program start-up. const string version2(“0.00 ” ); lut lut2( 7, 12, 48, 106 ); int *pi2 = new int( lut1[ 0 ] ); int ival2 = lut1[ 0 ]; The next question, then, is how does this initialization get accomplished during run-time.

17 OK, given the following program fragment Matrix identity; int main(){ // identity must be initialized by this point! // identity must be initialized by this point! Matrix m1 = identity; Matrix m1 = identity; return 0; return 0;} the language guarantees that identity is constructed prior to the first user statement of main(), and that it is destructed following the last statement of main(). A global object such as identity with an associated constructor and destructor is said to require both static initialization and deallocation.

18 Static Initialization: Why the Urgency? OK, given the following program fragment, why is the issue of when static initialization takes place an issue? Matrix identity( 1,0,0,0,0,1,0,0, 0,0,1,0,0,0,0,1 ); 0,0,1,0,0,0,0,1 ); int main() { Matrix m1 = identity; Matrix m1 = identity; //... //... return 0; return 0;}

19 Static Initialization: Why the Urgency? Unless identity is initialized before the first statement of main(), our program fails. In this case, it is the compiler’s responsibility to carry out the necessary initialization in a timely fashion. (We’ll see a case later in which the initialization becomes our responsibility.) The language guarantees just that. We are promised that identity is constructed prior to the first user statement of main(), and that it is destructed following the last statement of main(). A global object such as identity with an associated constructor and destructor is said to require both static initialization and deallocation.

20 Static Initialization at Start-up All global objects, whether complex or simple, are allocated within the program data segment. If an initial value is specified, and that initialize value can be evaluated at compile-time, the object is initialized with that value. Otherwise, a special initialization function (and special deallocation function, if necessary) is synthesized within the module under compilation. The non-constant initial expression is applied to the object within this function.

21 Static Initialization at Start-up For example, in our example, the program is rewritten something like the following (this is Pseudo-code): Matrix identity; // no constructor applied Matrix identity; // no constructor applied int main() int main() { // prior to execution beginning here, // prior to execution beginning here, // __sti__someName() and all other static // __sti__someName() and all other static // initialization functions must be invoked // initialization functions must be invoked Matrix m1 = identity; Matrix m1 = identity; // … // …} // compiler synthesize initialization function // compiler synthesize initialization function void __sti_someName(){ void __sti_someName(){identity.Matrix::Matrix( 1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1 ); 1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1 ); }

22 Static Initialization at Start-up If there are multiple objects within a file requiring static initialization, they are placed within the function in the order of their declaration. This is guaranteed by the language. (What is not guaranteed is the order that these initialization functions are invoked. We’ll look at that in a minute. So, for example, given the following set of complex global objects: const string version2( “0.00 ” ); vector lut2( lut1, lut1+4 ); int *pi2 = new int( lut1[ 0 ] ); int ival2 = lut1[ 0 ];

23 Static Initialization at Start-up // typical transformation const string version2; // no constructor vector lut2; // no constructor int *pi2 = 0; int ival2 = 0; void __sti_someName() void __sti_someName() { // Pseudo-code // Pseudo-code version2.string::string(“0.00 ” ); version2.string::string(“0.00 ” ); lut2.vector::vector( lut1, lut1+4 ); lut2.vector::vector( lut1, lut1+4 ); pi2 = new int( lut1[ 0 ] ); pi2 = new int( lut1[ 0 ] ); ival2 = lut1[ 0 ]; ival2 = lut1[ 0 ];}

24 Static Initialization at Start-up The job of the compilation system, then, is to identify and invoke all the static initialization functions within the program executable. Moreover, to do that prior to the beginning of main(). Again, within a module, the order of initialization is strictly defined: it is the textual order of declaration. The order of destruction is the reverse. Unfortunately, the order of initialization across modules is left undefined by C++ Standard. Using objects requiring static initialization across modules requires some special programming. Let’s first look at the problem, then illustrate one programmer solution.

25 Problem Illustration #include #include #include "my_static_object.h" extern my_static_object *p; // foo makes use of p // foo and p are defined in separate modules extern int foo(); // we want to use p and foo() here – // we have no way within the language // language to force the initialization of p. int iv = p->bar(); int iv2 = foo(); int main() { // !! core dumps before reaching here. // !! core dumps before reaching here. cout << "beginning main: " << p << endl; cout << "beginning main: " << p << endl;}

26 The Problem Statement We need to guarantee that when a user includes a header file in which one or more global objects are declared that require static initialization, that those objects Are initialized in that module in which the header file is included. But … are initialized just once although it is likely that multiple modules will include the header file. As an example of the problem, think of cout, cin, and cerr, each of which must be statically initialized before a use and which are included in hundreds of files.

27 A Schwarz Counter Solution Jerry Schwarz, the designer of the original iostream library, came up with a solution that is now generally bears his name: Schwarz Counter. Consider our static_object class, as follows: class my_static_object { public:my_static_object(); int foo() const { return _ival; } private: int _ival; }; // the external object we need to initialize extern my_static_object *p;

28 A Schwarz Counter Solution Within the header file of the class an auxiliary class – some call it a helper class – and a static object of that class are introduced: class my_stat_obj_init { public: my_stat_obj_init( ); ~my_stat_obj_init();private: static int init_count; static int init_val; }; // the Schwarz counter static object Static my_stat_obj_init obj;

29 What’s Going on? The auxiliary class maintains a static data member that keeps a reference count. This member is incremented with each constructor call and decremented with each destructor call. If it is 0 prior to being incremented, the global object we care about is initialized within the constructor: my_stat_obj_init::my_stat_obj_init(){ if ( init_count++ ) return; return; // this is the whole point of the class // this is the whole point of the class p = new my_static_object( init_val ); p = new my_static_object( init_val );}

30 Destructor & Static Members The cost of the static object initialization of obj is the constructor call, and generally a word of storage for each module it is included in. The benefit is that it does not require any explicit work from the user. The destructor and static data declarations look as follows: my_stat_obj_init::~my_stat_obj_init(){ if ( -- init_count ) return; return; delete p; }; int my_stat_obj_init::init_count; int my_stat_obj_init::init_val = 1024;

31 Potential Drawback … If possible, I recommend not using global objects, in particular global objects requiring static initialization. A singleton object that allocates itself on a first use is one possible alternative. It is important for the C++ programmer to Recognize the difference between simple and global complex object. Recognize when a global complex object may be accessed by complex global objects in other modules and program such that the global object accessed is initialized. Hopefully this unit has clarified the issue and suggested at least one solution.