Pointers and references

Slides:



Advertisements
Similar presentations
SPL/2010 Pointers and Parameter Passing in C++ 1.
Advertisements

Pointers Typedef Pointer Arithmetic Pointers and Arrays.
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.
This set of notes is adapted from that provided by “Computer Science – A Structured Programming Approach Using C++”, B.A. Forouzan & R.F. Gilberg, Thomson.
Pointers “Absolute C++” Section 10.1
Rossella Lau Lecture 8, DCO10105, Semester B, DCO10105 Object-Oriented Programming and Design  Lecture 8: Polymorphism & C++ pointer  Inheritance.
ARRAYS AND POINTERS Although pointer types are not integer types, some integer arithmetic operators can be applied to pointers. The affect of this arithmetic.
C++ / G4MICE Course Session 3 Introduction to Classes Pointers and References Makefiles Standard Template Library.
 2006 Pearson Education, Inc. All rights reserved Classes: A Deeper Look.
1 CISC181 Introduction to Computer Science Dr. McCoy Lecture 19 Clicker Questions November 3, 2009.
C++ Programming: Program Design Including Data Structures, Fourth Edition Chapter 13: Pointers, Classes, Virtual Functions, and Abstract Classes.
C++ Programming: From Problem Analysis to Program Design, Fourth Edition Chapter 14: Pointers, Classes, Virtual Functions, and Abstract Classes.
Values, variables and types © Allan C. Milne v
CSE 232: C++ pointers, arrays, and references Overview of References and Pointers Often need to refer to another object –Without making a copy of the object.
Computer Science and Software Engineering University of Wisconsin - Platteville 2. Pointer Yan Shi CS/SE2630 Lecture Notes.
1 C++ Classes and Data Structures Jeffrey S. Childs Chapter 4 Pointers and Dynamic Arrays Jeffrey S. Childs Clarion University of PA © 2008, Prentice Hall.
Pointers and Dynamic Memory Allocation Copyright Kip Irvine 2003, all rights reserved. Revised 10/28/2003.
Object-Oriented Programming in C++
Pointers. What is pointer l Everything stored in a computer program has a memory address. This is especially true of variables. char c=‘y’; int i=2; According.
Copyright 2005, The Ohio State University 1 Pointers, Dynamic Data, and Reference Types Review on Pointers Reference Variables Dynamic Memory Allocation.
CS 376b Introduction to Computer Vision 01 / 23 / 2008 Instructor: Michael Eckmann.
1 Classes II Chapter 7 2 Introduction Continued study of –classes –data abstraction Prepare for operator overloading in next chapter Work with strings.
ICOM 4035 – Data Structures Dr. Manuel Rodríguez Martínez Electrical and Computer Engineering Department Lecture 2 – August 23, 2001.
Copyright © 2014 Pearson Addison-Wesley. All rights reserved. Chapter 9 Pointers and Dynamic Arrays.
Pointers and Dynamic Memory Allocation
Memory Management.
Dynamic Storage Allocation
EGR 2261 Unit 11 Pointers and Dynamic Variables
Pointers and Dynamic Arrays
Data Types In Text: Chapter 6.
Overview 4 major memory segments Key differences from Java stack
CSE 374 Programming Concepts & Tools
Chapter 13: Pointers, Classes, Virtual Functions, and Abstract Classes
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
Lecture 7 Arrays, Dynamic Arrays & Copy Constructors “Absolute C++”
Classes.
Pointers and Pointer-Based Strings
Student Book An Introduction
Pointers and References
This pointer, Dynamic memory allocation, Constructors and Destructor
Pointers and Dynamic Variables
Dynamically Allocated Memory
Chapter 12: Pointers, Classes, Virtual Functions, and Abstract Classes
Object Oriented Programming COP3330 / CGS5409
Overview 4 major memory segments Key differences from Java stack
Chapter 15 Pointers, Dynamic Data, and Reference Types
Chapter 14: Pointers, Classes, Virtual Functions, and Abstract Classes
Pointers, Dynamic Data, and Reference Types
Initialization List.
Built-In (a.k.a. Native) Types in C++
Pointers.
Classes and Objects.
Pointers and References
Overloading functions
9-10 Classes: A Deeper Look.
Pointers Pointers point to memory locations
Pointers and Pointer-Based Strings
Java Programming Language
Pointers, Dynamic Data, and Reference Types
Pointers and references
9-10 Classes: A Deeper Look.
Classes and Objects Object Creation
四時讀書樂 (春) ~ 翁森 山光照檻水繞廊,舞雩歸詠春風香。 好鳥枝頭亦朋友,落花水面皆文章。 蹉跎莫遣韶光老,人生唯有讀書好。
4.1 Introduction Arrays A few types Structures of related data items
SPL – PS3 C++ Classes.
SPL – PS2 C++ Memory Handling.
Initialization List.
Presentation transcript:

Pointers and references Lecture 3 Pointers and references

Introduction In Java: there were only primitive types and Objects. Primitives were always allocated on the stack, and Objects on the heap. In C++: both primitives and objects may be allocated on the stack or on the heap. In C/C++: anything can be reached by holding an address to its location. The type of a variable that holds an address to a memory location is called a pointer.

Introduction The main memory can be thought of as an array (of bytes). A pointer is actually only an index in this array (In essence: an int). Types (like int, long, double, etc.) usually require more than one byte - the pointer will hold the address to the first byte in the sequence of bytes holding the value. Example: the int value 7 will be stored: 07 00 00 00 (32bit). This value may be reside on the memory starting in the address 51084, therefore: int *p=51084; The value inside this address is 7 while the address itself is 51084.

Introduction Pointers are primitive types in themselves. They hold the memory address of a primitive or an object which resides either on the heap or on the stack. A pointer to a type type_a is of type type_a*, where type_a* is a primitive type, regardless of the type type_a. Supposed that a is a pointer to some memory of a variable. Reading this variable will be done by *a.

Example The following takes place: A primitive of type int* is allocated. On main’s activation frame. The space allocated is associated with i_ptr. A primitive int is allocated on the heap. initialized to 10. The address of the allocated int is in i_ptr. The operator << of std::cout is passed the content (by value) i_ptr points to. That is: std::cout's operator << is called with the integer 10. #include <iostream> int main() { int *i_ptr = new int(10); std::cout << *i_ptr << std::endl; return 0; }

The memory structure

Another Example class Cow { private: int _id; public: //member initialization list Cow(int id): _id(id) {} int getId() const { return this->_id; } void setId(int newId) { this->_id = newId; void moooo() const { std::cout << "moooo: " << this->_id << std::endl;

Member initialization list The constructor of the class initialize the fields using a member initialization list (an option to initialize class members). The member initialization is executed before the body of the function. It is possible to initialize data members inside the constructor body but not advised for the following two reasons: Implicit call to default constructor - when a data member is itself a class object, not initializing it via the initialization list means implicitly calling its default constructor! If you do initialize it in the body of the constructor you are actually initializing it twice. Const members of a class can only be initialized via member initialization list.

Member initialization list The order the initialization happens is according to the order the member vars are declared (not the order in the initialization list). It is hence a convention to keep the order of the list as the order of the declaration.

Some more code details Whenever member methods of a class T are executed, this is always of type T*, and points to the location, in memory, in which the instance we are working on resides. When a method of an object does not change the object's internal state, we define the method as const. It is good practice to mark each "logical" const method as const. The C++ operator -> is used to access the members and methods of objects via a pointer to the object. Accessing members / methods of an object not through a pointer is done using the . (dot) operator, as in Java.

Back to the example int main() { Cow bety(482528404); Cow *ula = new Cow(834579343); bety.moooo(); ula->moooo(); return 0; } class Cow { private: int _id; public: //member initialization list Cow(int id): _id(id) {} int getId() const { return this->_id; void setId(int newId) { this->_id = newId; void moooo() const { std::cout << "moooo: " << this->_id << std::endl;

Back to the example The following takes place: Space for a Cow is allocated on the activation frame of the main function, and the constructor of Cow is called with 482528404. this points to the address of the space on the stack. The allocated space is associated with the variable bety. Space for a pointer Cow* is allocated on the activation frame of the main function. It is associated with the variable ula. Space for a Cow is allocated on the heap, and its constructor is called with 834579343. this points to the address of the space on the heap. The address of the newly allocated Cow is saved in ula int main() { Cow bety(482528404); Cow *ula = new Cow(834579343); bety.moooo(); ula->moooo(); return 0; }

Back to the example The following takes place: Space for a Cow is allocated on the activation frame of the main function, and the constructor of Cow is called with 482528404. this points to the address of the space on the stack. The allocated space is associated with the variable bety. Space for a pointer Cow* is allocated on the activation frame of the main function. It is associated with the variable ula. Space for a Cow is allocated on the heap, and its constructor is called with 834579343. this points to the address of the space on the heap. The address of the newly allocated Cow is saved in ula int main() { Cow bety(482528404); Cow *ula = new Cow(834579343); bety.moooo(); ula->moooo(); return 0; }

Dereferencing a Pointer and the "Address Of" operator We saw how to dereference a pointer, using the * operator: (*ula).moooo(); It is valid, since (*ula) is of type Cow, and can be accessed using the . (dot) operator. The same can be done with ula->moooo(); We sometimes would like to get the address of something. To this end there is the "address of" operator, &. int i = 10; int *i_ptr = &i; i_ptr holds the address in which i is stored on the stack.

Pointers arguments for a function void inc(int *i_ptr){ (*i_ptr)++; } int i = 0; inc(&i); std::cout << i << endl; and the output will be 1.

const pointers Any type in C++ can be marked as const, which means that its value cannot be changed. Two roles: Hints the user that this value is not going to change. Prevents bugs caused by changing this variable by mistake. const pointer is declared by adding the const keyword after the type int *const i_ptr a const pointer to an int The pointer itself can not be changed – it must be set after such a decleration.

const pointers const int * x (int const * x) x is pointer to a constant integer Can also be int const * x (const int * x) int * const x  x is a constant pointer to an integer int const * const x X is a const pointer to a const integer

lvalues and rvalues Every C++ expression is either an lvalue or an rvalue. An lvalue refers to an object that persists beyond a single expression. An lvalue is an object that has a name. All variables, including nonmodifiable (const) variables, are lvalues. An rvalue is a temporary value, that does not persist beyond the expression that uses it.

lvalues and rvalues: example int main() { int x = 3 + 4; print(x); } x is an lvalue because it persists beyond the expression that defines it. 3 + 4 is an rvalue because it evaluates to a temporary value that does not persist beyond the expression that defines it. lvalues are values that can appear in the left side of an assignment while rvalue are the rest (you can write x=3+4 and not 3+4=x).

The concept of references C++ supports the concept of References. Two types of references: lvalue references and rvalue references. lvalue references (this lecture): An lvalue reference is like a const pointer to an lvalue (without using any pointer notations). A reference may only be assigned once, when it is declared (which is called the initialization of the reference) It may not be altered to reference something else later.

Example: int i=0; int &i_ref = i; i_ref++; std::cout<<i<<std::endl; The output, not surprisingly, is 1. We can have a reference to any type by adding & after the type. However, we cannot have references to references (this is illegal).

Const lvalue References lvalue references can only accept lvalues. int foo() { return 42; } int x = 10; int& i = 4; //illegal - 4 is not an lvalue int& j = x + 1; //illegal - again - not an lvalue int& k = foo(); //not an lvalue too!!   const int& s = foo(); //this works! wait what?

Const lvalue References const int& s = foo(); //this works! wait what? This is a C++ feature… the code is valid and does exactly what it appears to do. Normally, a temporary object (i.e., an rvalue) lasts only until the end of the full expression in which it appears. However, C++ specifies that binding a temporary object to a reference to const on the stack lengthens the lifetime of the temporary to the lifetime of the reference itself, and thus avoids what would otherwise be a common dangling-reference error. The temporary returned by foo() lives until s get out of scope. This only applies to stack-based references.

Parameter Passing All parameters are either 'in' parameters or 'out' parameters. 'in' parameters are information passed to the function, which the function does not need to change. Any operation on an 'in' parameter are not visible outside of the function. 'out' parameters are meant as a side-channel from which the function may return information, in addition to the return value. Any changes made to 'out' parameters are visible outside the scope of the function.

Parameter Passing In Java there are only 2 forms of (implicit) passing parameters: primitives are passed by value (as 'in' parameters). Objects by reference (possible 'out' parameters). In C++ there are 3 forms for parameter passing. All of them explicit (the programmer must explicitly state which method to use). C++ allows passing parameters By value (as 'in' parameters). By pointer (either ‘in’ or ‘out’). By reference (either ‘in’ or ‘out’).

By value void byVal(int i, Cow mooo){ mooo.setId(i); } Cow hemda(20); byVal(30, hemda); std::cout << hemda.getId() << std::endl; The output is 20. When we call byVal, both 30 and the entire content of hemda are copied, and placed on the activation frame. byVal performs all of its operations on these local copies only

By Pointer If we don’t want to copy objects or want to change the parameter we can use pointers. void byPointer(int i, Cow *mooo){ mooo->setId(i); } Cow hemda(20); byPointer(30, &hemda); std::cout << hemda.getId() << std::endl; The output is 30. byPointer received a pointer to the location of hemda on the activation frame, and changed its id.

By reference (lvalue) When we wish to refrain from using pointers, which are inherently unsafe, we may use references. void byReference(int i, Cow &mooo){     mooo.setId(i); } Cow hemda(20); byReference(30, hemda); std::cout << hemda.getId() << std::endl; This code produces the same output as before (30), but we did not have to pass pointers. Moreover, the compiler is allowed to optimize the reference beyond the "const pointer" abstraction from above.

When to Use Each Form of Parameter Passing? In parameters: When we are not willing to pay the cost of copying and constructing a new object we will use a const reference (or pointer). void func foo(Cow const& c_ref) Out parameters: we will use either by-reference or by-pointer but when is advisable to use each ?

Recommendations (common practices) For In parameters: If the data object is small, pass it by value. If the data object is an array, use a pointer (that's the only choice). Make the pointer a const. If the data object is a good-sized struct, use a const reference. If the data object is a class object, use a const reference. For Out parameters: If the data object is a built-in data type, use a pointer or a reference. If the data object is an array, use your only choice, a pointer. If the data object is a struct, or a class object, use a reference. When receiving a pointer check for nullity. (A reference cannot be null.)

Returning Values From Functions As in parameter passing, values can be returned either by value (copy), reference or pointer. When returning something by reference or pointer care should be taken not to return a reference or a pointer to the soon to be demolished activation frame. Cow& f(int x) { Cow c(x); return c; // THIS IS A TRAGIC MISTAKE // c would be undefined when the function returns. }

Another bad example g++ 1.cpp; ./a.out 0xbffff564 134513864 0xbffff564 134513864 g++ 1.cpp -O1; ./a.out 0xbffff564 1 0xbffff564 2 g++ 1.cpp -O2 ; ./a.out 0xbffff560 1 0xbffff564 134519000 g++ 1.cpp -O3 ; ./a.out 0xbffff574 1 0xbffff570 1 This is bad! we can not predict how our program will work! No flag is lifted for us, a.k.a no exception, no segmentation fault. It works every time differently. #include <iostream> int* f(){ int i = 1; cout << &i << endl; return &i; } void g(){ int k = 2; cout << &k << endl; void main() { int *i = f(); cout << *i << endl; g();

C++ arrays Let us start with a word of caution: unless you really need to, do not use arrays in C++. Use Vectors instead. We will see some reasons why later. Arrays in C++ are just blocks of continuous memory, which store data of the same type. The memory image of an array of integers which holds the number 5 in each cell looks like this:

C++ arrays Each cell is of size 4 bytes which corresponds to the size of int in this example.

C++ arrays Accessing cells of the array is done by dereferencing a pointer to the specific cell.  Suppose a pointer to start of an array: int *arr_ptr We can access the fourth cell by using: arr_ptr[3] Which is equal to *(arr_ptr+3) Notice the pointer arithmetic: We add 3 to arr_ptr, but we do not mean 3 bytes, but 3 ints. We add 3 times sizeof(int). This is true for every type of pointer: additions/subtractions are implicitly multiplied by the size of the data the pointer points at.

Arrays on the Heap Arrays may be allocated on the Stack or on the Heap.  Allocating an array on the heap is achieved using new [], and deallocating it is done by delete []. int *arr = new int[100]; std::cout << arr[2] << std::endl; delete [] arr; The output of this code will always be 0, since the new [] operator initializes the array's elements using their default constructor, which in the case of int initializes them to 0.

Arrays on the Heap Consider the code: Cow **cow_arr = new Cow*[100]; for (int i=0; i<100; i++) cow_arr[i] = new Cow(i); delete [] cow_arr; We initialize new Cow objects on the heap, store their pointers in cow_arr. When we call delete [], we expect that the array will be deallocated. However, each element in the array is a pointer This means that each individual Cows we allocated will not deleted! We will need to delete each Cow manually – before deleting the array!

Arrays on the Stack To allocate an array on the Stack, the array's size must be known in advance. Cow cow_arr[5]; Each Cow will be initialized using its default constructor. We may also tell the compiler how to initialize individual Cows: Cow cow_arr[5] = {Cow(1), Cow(21), Cow(454), Cow(8), Cow(88)}; Accessing cells of the array on the Stack is achieved in the same as through a pointer. cow_arr is basically a pointer to the beginning of the array of Cows.