SlideShare a Scribd company logo
Chapter 15 – vector and
Free Store
Use vector as the default!
– Alex Stepanov
Overview: evolving a vector type
(and spanning the low-level/high-level language gap in the process)
• Chapter 15
• Dealing with “raw” memory: pointers and free store
• Destructors
• Chapter 16
• Arrays and pointers
• Pointers and references
• C-style strings
• Alternatives to low level facilities: span, array, and string
• Chapter 17
• Copying and moving
• Essential operations for managing object lifecycles
• Chapter 18
• Templates and generic programming
• Exceptions and scope-based resource management and error handling
(RAII)
• Resource management pointers: unique_ptr and shared_ptr
Stroustrup/Programming/2024/Chapter15 3
Vector
•vector is the most useful container
• ISO standard
• Simple to use
• Compactly stores elements of a given type
• Efficient access
• Expands to hold any number of elements
• Optionally range-checked access
• the PPP version is range checked
•How is that done?
• That is, how is vector implemented?
• We'll answer that gradually, feature after feature
•Prefer vector for storing elements unless there's
a good reason not to
Stroustrup/Programming/2024/Chapter15 4
Building from the ground up
•The hardware provides memory and addresses
• Low level
• Untyped
• Fixed-sized chunks of memory
• No checking
• As fast as the hardware architects can make it
•The application builder needs something like a
vector
• Higher-level operations
• Type checked
• Size varies (as we get more data)
• Run-time range checking
• Close to optimally fast
Stroustrup/Programming/2024/Chapter15 5
Building from the ground up
• At the lowest level, close to the hardware, life’s
simple and brutal
• You have to program everything yourself
• You have no type checking to help you
• Run-time errors are found when data is corrupted or the
program crashes
• We want to get to a higher level as quickly as we can
• To become productive and reliable
• To use a language “fit for humans”
• Chapters 15-18 basically show all the steps needed
• The alternative to understanding is to believe in “magic”
• The techniques for building vector are the ones underlying
all higher-level work with data structures
Stroustrup/Programming/2024/Chapter15 6
Vector
•A vector
• Our Vector will gradually be improved to approximate
the standard vector
• Can hold an arbitrary number of elements
• Up to whatever physical memory and the operating system can handle
• That number can vary over time
• E.g. by using push_back()
• Example
Vector<double> age(4);
age[0]=.33; age[1]=22.0; age[2]=27.2; age[3]=54.2;
Stroustrup/Programming/2024/Chapter15 7
4
0.33 22.0 27.2 54.2
age:
age[0]: age[1]: age[2]: age[3]:
Vector
class Vector { // a very simplified vector of doubles (like
vector<double>)
int sz; // the number of elements (“the size”)
double* elem; // pointer to the first element
public:
Vector(int s); // constructor: allocate s elements,
let elem point to them
int size() const { return sz; } // the current size
};
•* means “pointer to” so double* is a “pointer to
double”
• What is a “pointer”?
• How do we make a pointer “point to” elements?
• How do we “allocate” elements?
Stroustrup/Programming/2024/Chapter15 8
Pointer values
•Pointer values are memory addresses
• Think of them as a kind of integer values
• The first byte of memory is 0, the next 1, and so
on
• A pointer p can hold the address of a memory
location
Stroustrup/Programming/2024/Chapter15 9
0 1 2 2^20-1
7
600
p 600
• A pointer points to an object of a given type
• E.g., a double* points to a double, not to a string
• A pointer’s type determines how the memory referred to by the pointer’s value is used
• E.g. ,what a double* points to can be added but not, say, concatenated
The computer’s memory
•As a program sees it
• Local variables “live on the stack” (including
function arguments)
• Global variables are “static data”
• The executable code is in “the code section”
Stroustrup/Programming/2024/Chapter15 10
Vector (constructor)
Vector::Vector(int s) // Vector's constructor
:sz(s), // store the size s in sz
elem(new double[s]) // allocate s doubles on the free store
// store a pointer to those doubles in elem
{
// Note: new does not initialize elements (but the standard vector
does)
}
Stroustrup/Programming/2024/Chapter15 11
Free store:
4
• new allocates memory from the free store and
returns a pointer to the allocated memory
• We use new to allocate objects that have to
outlive the function that creates them
A pointer
sz: elem:
The free store
(sometimes called "the heap“ or “dynamic
memory”)
• You request memory “to be allocated” “on the free store” by the
new operator
• The new operator returns a pointer to the allocated memory
• A pointer is the address of the first byte of the memory
• int* p = new int; // allocate one uninitialized int
// int* means “pointer to int”
• int* q = new int[7]; // allocate seven uninitialized ints
// “an array of 7 ints”
• double* pd = new double[n]; // allocate n uninitialized
doubles
• A pointer points to an object of its specified type
• A pointer does not know how many elements it points to
Stroustrup/Programming/2024/Chapter15 12
p:
q:
Access
•Individual elements
int* p1 = new int; // get (allocate) a new
uninitialized int
int* p2 = new int(5); // get a new int initialized to 5
int x = *p2; // get/read the value pointed to by
p2
// (or “get the contents of what p2
points to”)
// in this case, the integer 5
int y = *p1; // undefined: y gets an undefined
Stroustrup/Programming/2024/Chapter15 13
5
p2:
???
p1:
Access
[0] [1] [2]
[3] [4]
• Arrays (sequences of elements)
int* p3 = new int[5]; // get (allocate) 5 ints
// array elements are numbered [0],
[1], [2], …
p3[0] = 7; // write to (“set”) the 1st element
of p3
p3[1] = 9;
int x2 = p3[1]; // get the value of the 2nd element of p3
int x3 = *p3; // we can also use the dereference
operator * for an array
Stroustrup/Programming/2024/Chapter15 14
7 9
p3:
Pointer values
• Pointer values are memory addresses
• Think of them as a kind of integer values
• The first byte of memory is 0, the next 1, and so on
Stroustrup/Programming/2024/Chapter15 15
// you can see a pointer value (but you rarely need/want to):
int* p1 = new int(7); // allocate an int and initialize it to 7
double* p2 = new double(7); // allocate a double and initialize it to 7.0
cout << "p1==" << p1 << " *p1==" << *p1 << "n"; // p1==??? *p1==c
cout << "p2==" << p2 << " *p2==" << *p2 << "n"; // p2==??? *p2=7
0 1 2 2^20-1
7
p2 *p2
Access
• A pointer does not know the number of elements that
it's pointing to (only the address of the first
element)
double* p1 = new double;
*p1 = 7.3; // ok
p1[0] = 8.2; // ok
p1[17] = 9.4; // ouch! Undetected error
p1[-4] = 2.4; // ouch! Another undetected error
double* p2 = new double[100];
*p2 = 7.3; // ok
p2[17] = 9.4; // ok
p2[-4] = 2.4; // ouch! Undetected error
• Fortunately, we have ways of avoiding such errors
Stroustrup/Programming/2024/Chapter15 16
7.3
8.2
7.3
p1:
p2:
Access
• A pointer does not know the number of elements that
it's pointing to
double* p1 = new double;
double* p2 = new double[100];
p1[17] = 9.4; // error (obviously)
p1 = p2; // assign the value of p2 to p1
p1[17] = 9.4; // now ok: p1 now points to the array of
100 doubles
Stroustrup/Programming/2024/Chapter15 17
p1:
p2:
p1:
(after the assignment)
[0]: [99]:
Access
• A pointer does know the type of the object that it’s
pointing to
int* pi1 = new int(7);
int* pi2 = pi1; // ok: pi2 points to the same object as pi1
double* pd = pi1; // error: can’t assign an int* to a
double*
char* pc = pi1; // error: can’t assign an int* to a char*
• There are no implicit conversions between a pointer to one
value type to a pointer to another value type
• However, there are implicit conversions between value types:
*pc = 8; // ok: we can assign an int to a char
*pc = *pi1; // ok: we can assign an int to a char
Stroustrup/Programming/2024/Chapter15 18
7
7
pi1:
pc:
The null pointer
• Sometimes, we need to say “this pointer doesn’t point to
anything just now”
double* p = nullptr;
// …
If (p!=nullptr) // p points to something
*p = 7;
else
*p = 9; // No! never do this, p doesn’t point to
anything
• More concisely, we can leave out the !=nullptr
If (p) // p points to something, aka “p is valid’’
*p = 7;
• nullptr is commonly used to indicate
• End of a linked list
• No pointer value available just now
• No object to return a pointer to
Stroustrup/Programming/2024/Chapter15 20
A problem: memory leak
double* calc(int result_size, int max)
{
double* p = new double[max]; // allocate max doubles on free
store
double* result = new double[result_size];
// … use p to calculate results to be put in result …
return result;
}
double* r = calc(200,100); // oops!
• We “forgot” to give the memory allocated by new back to the
free store
• That doesn’t happen automatically (“no garbage collection”)
• Lack of de-allocation (usually called “memory leaks”) can be a
serious problem in real-world programs
Stroustrup/Programming/2024/Chapter15 21
We can give memory back to the free
store: detete
double* calc1(int result_size, int max)
{
double* tmp = new double[max]; // allocate max doubles on free
store
double* result = new double[result_size];
// … use tmp to calculate results to be put in result …
delete[] tmp; // return the memory pointed to by
tmp to the free store
return result;
}
double* r = calc1(200,100); // oops!
// … use r …
delete[ ] r; // return the memory pointed to by r to the
free store
Stroustrup/Programming/2024/Chapter15 22
Memory leaks – resource leaks
• A program that needs to run “forever” can’t afford any memory
leaks
• An operating system is an example of a program that “runs forever”
• If a function leaks 8 bytes every time it is called, how many
days can it run before it has leaked/lost a megabyte?
• Trick question: not enough data to answer, but about 130,000 calls
• All memory is returned to the system at the end of the program
• If you run using an operating system (Windows, Unix, whatever)
• Program that runs to completion with predictable memory usage
may leak without causing problems
• i.e., memory leaks aren’t “good/bad” but they can be a major problem in
specific circumstances
• Memory leaks is a major real-world problem
• Memory leaks is just a special case of resource leaks
• E.g., files, locks, sockets
Stroustrup/Programming/2024/Chapter15 23
Memory leaks
• Another way to get a memory
leak
void f()
{
double* p = new double[27];
// …
p = new double[42];
// …
delete[] p;
}
// 1st array (of 27 doubles)
leaked
Stroustrup/Programming/2024/Chapter15 24
p:
2nd value
1st value
Memory leaks
•How do we systematically and simply avoid
memory leaks?
• Use resource handles
• Use vector, etc.
• don't mess directly with new and delete
• Or use a garbage collector
• A garbage collector is a program the keeps track of all
of your allocations and returns unused free-store
allocated memory to the free store
• Not common in C++
• not covered in this course; see
http://www.stroustrup.com/C++.html
• Unfortunately, a garbage collector doesn’t prevent all
resource leaks
• Only memory leaks Stroustrup/Programming/2024/Chapter15 25
A problem: memory leak
void f(int x)
{
Vector v(x); // define a Vector (which allocates x
doubles on the free store)
// … use v …
// give the memory allocated by v back to the free store
// but how? (Vector's elem data member is private)
}
Stroustrup/Programming/2024/Chapter15 26
Vector (destructor)
// a very simplified Vector of doubles:
class Vector {
int sz; // the size
double* elem; // a pointer to the elements
public:
Vector(int s) :sz(s), elem(new double[s]) { } // constructor:
allocates/acquires memory
~Vector() { delete[ ] elem; } // destructor: de-
allocates/releases memory
// …
};
• Note: this is an example of a general and important
technique:
• acquire resources in a constructor
• release them in the destructor
• Examples of resources: memory, files, locks, threads,
sockets
Stroustrup/Programming/2024/Chapter15 27
Implicitly give memory back to the free
store
Vector<double> calc2(int result_size, int max)
{
Vector<double> tmp(max); // allocate max doubles
on free store
Vector<double> result(result_size);
// … use tmp to calculate results to be put in result …
return result;
} // tmp destroyed upon return
void user()
{
// …
auto res = calc2(200,100); // oops!
// … use r …
} // res destroyed upon return
Stroustrup/Programming/2024/Chapter15 28
Simpler and probably more efficient
than using new and delete explicitly
(yes, we can avoid copying a result v
- Next lecture)
Free store summary
• Allocate using new
• New allocates an object on the free store, sometimes initializes
it, and returns a pointer to it
• int* pi = new int; // default initialization (none for
int)
• char* pc = new char('a'); // explicit initialization
• double* pd = new double[10]; // allocation of (uninitialized)
array
• New throws a bad_alloc exception if it can't allocate (out of
memory)
• Deallocate using delete and delete[ ]
• delete and delete[ ] return the memory of an object allocated by
new to the free store so that the free store can use it for new
allocations
• delete pi; // deallocate an individual object
• delete pc; // deallocate an individual object
• delete[ ] pd; // deallocate an array
• Delete of a zero-valued pointer ("the null pointer") does nothing
Stroustrup/Programming/2024/Chapter15 29
Avoid “naked new” and “naked delete”
• Manual resource allocation and deallocation is error-prone
• We forget to hand resources back (Ask any librarian)
• We use pointers after the memory they point to has been deleted
• Use of “raw pointers” to manage memory leads to overuse of pointers
• Using vector leads to simpler code
• Compare calc1() and calc2()
• See the following lectures and chapters
Stroustrup/Programming/2024/Chapter15 30
Generated destructors
• If a member of a class has a destructor, then that destructor
will be called when the object containing the member is
destroyed.
struct Customer {
string name;
vector<string> addresses;
// ...
};
void some_fct()
{
Customer fred { "Fred", {"17 Oak St.", "232 Rock Ave."}};
// ... use fred ...
}
• That saves us a lot of work
Stroustrup/Programming/2024/Chapter15 31
Virtual destructors
• Destructors work correctly in class hierarchies
• Provided you declare the destructor virtual
Shape* fct()
{
Text tt {Point{200,200},"Anya"}; // local Text variable
// ...
return new Text{Point{100,100},"Courtney"}; // Text object
on the free store
}
void user()
{
Shape* q = fct();
// ... use the Shape without caring exactly which kind of shape it
is ...
delete q; // Shape’s destructor is virtual so
Text::~Text() is called if *q is a Text
Stroustrup/Programming/2024/Chapter15 32
But, what about “no naked deletes”?
• Use “resource-manegement” pointers ()
unique_ptr<Shape> fct()
{
Text tt {Point{200,200},"Annemarie"}; // local Text variable
// ...
return make_unique<Text>(Point{100,100},"Nicholas"); // Text object on the free store
}
void user()
{
unique_ptr<Shape> q = fct();
// ... use the Shape without caring exactly which kind of shape it is ...
}
• Equivalent to the previous example, but simpler
Stroustrup/Programming/2024/Chapter15 33
Access to elements
• But our Vector doesn’t have access operations
• So, let’s add very simple ones
class Vector { // a very simplified vector of doubles
public:
Vector(int s) :sz{s}, elem{new double[s]} { /* ... */ } // constructor
~Vector() { delete[] elem; } // destructor
int size() const { return sz; } // the current size
double get(int n) const { return elem[n]; } // access: read
void set(int n, double v) { elem[n]=v; } // access: write
private:
int sz; // the size
double* elem; // a pointer to the elements
};
Stroustrup/Programming/2024/Chapter15 34
Access to elements
• Not very elegant
• But it’ll do for now
Vector v(5);
for (int i=0; i<v.size(); ++i) {
v.set(i,1.1*i);
cout << "v[" << i << "]==" << v.get(i) << 'n';
}
Stroustrup/Programming/2024/Chapter15 35
Reminder
•Why look at the Vector implementation?
• To see how the standard library vector really works
• To introduce basic concepts and language features
• Free store (heap)
• Copying
• Dynamically growing data structures
• To see how to directly deal with memory
• To introduce the techniques and concepts we need to
understand C
• Including the dangerous ones (and see how to avoid those in
C++)
• To demonstrate class design techniques
• To see examples of “neat” code and good design
Stroustrup/Programming/2024/Chapter15 36
Next lecture
• We’ll see how we can change our Vector’s implementation to
better allow for changes in the number of elements. Then we’ll
modify Vector to take elements of an arbitrary type and add
range checking. That’ll imply looking at templates and
revisiting exceptions.
Stroustrup/Programming/2024/Chapter15 37

More Related Content

PDF
C++_notes.pdf
PDF
Memory Management for C and C++ _ language
PDF
Functions And Header Files In C++ | Bjarne stroustrup
PPTX
pointers in c programming - example programs
PDF
Object Oriented Programming using C++ - Part 4
PDF
dynamic-allocation.pdf
PPTX
Introduction to C ++.pptx
PPTX
C++ Core Guidelines
C++_notes.pdf
Memory Management for C and C++ _ language
Functions And Header Files In C++ | Bjarne stroustrup
pointers in c programming - example programs
Object Oriented Programming using C++ - Part 4
dynamic-allocation.pdf
Introduction to C ++.pptx
C++ Core Guidelines

Similar to How vectors work in C++ and their allocation of memory (20)

PDF
C programming day#2.
PPTX
Intro To C++ - Class #18: Vectors & Arrays
PDF
Resource wrappers in C++
PDF
Linked list
DOCX
Arrry structure Stacks in data structure
PPTX
Build 2016 - B880 - Top 6 Reasons to Move Your C++ Code to Visual Studio 2015
PDF
(5) cpp dynamic memory_arrays_and_c-strings
PPTX
Return of c++
PPTX
#OOP_D_ITS - 2nd - C++ Getting Started
PPTX
Introduction Of C++
PPT
Arrays in c programing. practicals and .ppt
PDF
Memory Management with Java and C++
PDF
C# 7 development
PDF
Python for web security - beginner
PPTX
Dynamic Memory Allocation.pptx for c language and basic knowledge.
PPTX
PDF
Session 2 - Objective-C basics
PPTX
Operating System Assignment Help
PPTX
Data structure and Algorithms (C++).pptx
PPT
79744777- FULL AND DETAILED LEVEL OF Pointers-in-c-Presentation.ppt
C programming day#2.
Intro To C++ - Class #18: Vectors & Arrays
Resource wrappers in C++
Linked list
Arrry structure Stacks in data structure
Build 2016 - B880 - Top 6 Reasons to Move Your C++ Code to Visual Studio 2015
(5) cpp dynamic memory_arrays_and_c-strings
Return of c++
#OOP_D_ITS - 2nd - C++ Getting Started
Introduction Of C++
Arrays in c programing. practicals and .ppt
Memory Management with Java and C++
C# 7 development
Python for web security - beginner
Dynamic Memory Allocation.pptx for c language and basic knowledge.
Session 2 - Objective-C basics
Operating System Assignment Help
Data structure and Algorithms (C++).pptx
79744777- FULL AND DETAILED LEVEL OF Pointers-in-c-Presentation.ppt
Ad

Recently uploaded (20)

PDF
Complications of Minimal Access Surgery at WLH
PPTX
human mycosis Human fungal infections are called human mycosis..pptx
PDF
Black Hat USA 2025 - Micro ICS Summit - ICS/OT Threat Landscape
PDF
VCE English Exam - Section C Student Revision Booklet
PPTX
Pharmacology of Heart Failure /Pharmacotherapy of CHF
PPTX
Institutional Correction lecture only . . .
PPTX
Lesson notes of climatology university.
PDF
Module 4: Burden of Disease Tutorial Slides S2 2025
PDF
OBE - B.A.(HON'S) IN INTERIOR ARCHITECTURE -Ar.MOHIUDDIN.pdf
PPTX
Pharma ospi slides which help in ospi learning
PDF
O7-L3 Supply Chain Operations - ICLT Program
PDF
O5-L3 Freight Transport Ops (International) V1.pdf
PDF
Computing-Curriculum for Schools in Ghana
PPTX
GDM (1) (1).pptx small presentation for students
PDF
A GUIDE TO GENETICS FOR UNDERGRADUATE MEDICAL STUDENTS
PDF
STATICS OF THE RIGID BODIES Hibbelers.pdf
PPTX
Final Presentation General Medicine 03-08-2024.pptx
PPTX
school management -TNTEU- B.Ed., Semester II Unit 1.pptx
PPTX
master seminar digital applications in india
PDF
102 student loan defaulters named and shamed – Is someone you know on the list?
Complications of Minimal Access Surgery at WLH
human mycosis Human fungal infections are called human mycosis..pptx
Black Hat USA 2025 - Micro ICS Summit - ICS/OT Threat Landscape
VCE English Exam - Section C Student Revision Booklet
Pharmacology of Heart Failure /Pharmacotherapy of CHF
Institutional Correction lecture only . . .
Lesson notes of climatology university.
Module 4: Burden of Disease Tutorial Slides S2 2025
OBE - B.A.(HON'S) IN INTERIOR ARCHITECTURE -Ar.MOHIUDDIN.pdf
Pharma ospi slides which help in ospi learning
O7-L3 Supply Chain Operations - ICLT Program
O5-L3 Freight Transport Ops (International) V1.pdf
Computing-Curriculum for Schools in Ghana
GDM (1) (1).pptx small presentation for students
A GUIDE TO GENETICS FOR UNDERGRADUATE MEDICAL STUDENTS
STATICS OF THE RIGID BODIES Hibbelers.pdf
Final Presentation General Medicine 03-08-2024.pptx
school management -TNTEU- B.Ed., Semester II Unit 1.pptx
master seminar digital applications in india
102 student loan defaulters named and shamed – Is someone you know on the list?
Ad

How vectors work in C++ and their allocation of memory

  • 1. Chapter 15 – vector and Free Store Use vector as the default! – Alex Stepanov
  • 2. Overview: evolving a vector type (and spanning the low-level/high-level language gap in the process) • Chapter 15 • Dealing with “raw” memory: pointers and free store • Destructors • Chapter 16 • Arrays and pointers • Pointers and references • C-style strings • Alternatives to low level facilities: span, array, and string • Chapter 17 • Copying and moving • Essential operations for managing object lifecycles • Chapter 18 • Templates and generic programming • Exceptions and scope-based resource management and error handling (RAII) • Resource management pointers: unique_ptr and shared_ptr Stroustrup/Programming/2024/Chapter15 3
  • 3. Vector •vector is the most useful container • ISO standard • Simple to use • Compactly stores elements of a given type • Efficient access • Expands to hold any number of elements • Optionally range-checked access • the PPP version is range checked •How is that done? • That is, how is vector implemented? • We'll answer that gradually, feature after feature •Prefer vector for storing elements unless there's a good reason not to Stroustrup/Programming/2024/Chapter15 4
  • 4. Building from the ground up •The hardware provides memory and addresses • Low level • Untyped • Fixed-sized chunks of memory • No checking • As fast as the hardware architects can make it •The application builder needs something like a vector • Higher-level operations • Type checked • Size varies (as we get more data) • Run-time range checking • Close to optimally fast Stroustrup/Programming/2024/Chapter15 5
  • 5. Building from the ground up • At the lowest level, close to the hardware, life’s simple and brutal • You have to program everything yourself • You have no type checking to help you • Run-time errors are found when data is corrupted or the program crashes • We want to get to a higher level as quickly as we can • To become productive and reliable • To use a language “fit for humans” • Chapters 15-18 basically show all the steps needed • The alternative to understanding is to believe in “magic” • The techniques for building vector are the ones underlying all higher-level work with data structures Stroustrup/Programming/2024/Chapter15 6
  • 6. Vector •A vector • Our Vector will gradually be improved to approximate the standard vector • Can hold an arbitrary number of elements • Up to whatever physical memory and the operating system can handle • That number can vary over time • E.g. by using push_back() • Example Vector<double> age(4); age[0]=.33; age[1]=22.0; age[2]=27.2; age[3]=54.2; Stroustrup/Programming/2024/Chapter15 7 4 0.33 22.0 27.2 54.2 age: age[0]: age[1]: age[2]: age[3]:
  • 7. Vector class Vector { // a very simplified vector of doubles (like vector<double>) int sz; // the number of elements (“the size”) double* elem; // pointer to the first element public: Vector(int s); // constructor: allocate s elements, let elem point to them int size() const { return sz; } // the current size }; •* means “pointer to” so double* is a “pointer to double” • What is a “pointer”? • How do we make a pointer “point to” elements? • How do we “allocate” elements? Stroustrup/Programming/2024/Chapter15 8
  • 8. Pointer values •Pointer values are memory addresses • Think of them as a kind of integer values • The first byte of memory is 0, the next 1, and so on • A pointer p can hold the address of a memory location Stroustrup/Programming/2024/Chapter15 9 0 1 2 2^20-1 7 600 p 600 • A pointer points to an object of a given type • E.g., a double* points to a double, not to a string • A pointer’s type determines how the memory referred to by the pointer’s value is used • E.g. ,what a double* points to can be added but not, say, concatenated
  • 9. The computer’s memory •As a program sees it • Local variables “live on the stack” (including function arguments) • Global variables are “static data” • The executable code is in “the code section” Stroustrup/Programming/2024/Chapter15 10
  • 10. Vector (constructor) Vector::Vector(int s) // Vector's constructor :sz(s), // store the size s in sz elem(new double[s]) // allocate s doubles on the free store // store a pointer to those doubles in elem { // Note: new does not initialize elements (but the standard vector does) } Stroustrup/Programming/2024/Chapter15 11 Free store: 4 • new allocates memory from the free store and returns a pointer to the allocated memory • We use new to allocate objects that have to outlive the function that creates them A pointer sz: elem:
  • 11. The free store (sometimes called "the heap“ or “dynamic memory”) • You request memory “to be allocated” “on the free store” by the new operator • The new operator returns a pointer to the allocated memory • A pointer is the address of the first byte of the memory • int* p = new int; // allocate one uninitialized int // int* means “pointer to int” • int* q = new int[7]; // allocate seven uninitialized ints // “an array of 7 ints” • double* pd = new double[n]; // allocate n uninitialized doubles • A pointer points to an object of its specified type • A pointer does not know how many elements it points to Stroustrup/Programming/2024/Chapter15 12 p: q:
  • 12. Access •Individual elements int* p1 = new int; // get (allocate) a new uninitialized int int* p2 = new int(5); // get a new int initialized to 5 int x = *p2; // get/read the value pointed to by p2 // (or “get the contents of what p2 points to”) // in this case, the integer 5 int y = *p1; // undefined: y gets an undefined Stroustrup/Programming/2024/Chapter15 13 5 p2: ??? p1:
  • 13. Access [0] [1] [2] [3] [4] • Arrays (sequences of elements) int* p3 = new int[5]; // get (allocate) 5 ints // array elements are numbered [0], [1], [2], … p3[0] = 7; // write to (“set”) the 1st element of p3 p3[1] = 9; int x2 = p3[1]; // get the value of the 2nd element of p3 int x3 = *p3; // we can also use the dereference operator * for an array Stroustrup/Programming/2024/Chapter15 14 7 9 p3:
  • 14. Pointer values • Pointer values are memory addresses • Think of them as a kind of integer values • The first byte of memory is 0, the next 1, and so on Stroustrup/Programming/2024/Chapter15 15 // you can see a pointer value (but you rarely need/want to): int* p1 = new int(7); // allocate an int and initialize it to 7 double* p2 = new double(7); // allocate a double and initialize it to 7.0 cout << "p1==" << p1 << " *p1==" << *p1 << "n"; // p1==??? *p1==c cout << "p2==" << p2 << " *p2==" << *p2 << "n"; // p2==??? *p2=7 0 1 2 2^20-1 7 p2 *p2
  • 15. Access • A pointer does not know the number of elements that it's pointing to (only the address of the first element) double* p1 = new double; *p1 = 7.3; // ok p1[0] = 8.2; // ok p1[17] = 9.4; // ouch! Undetected error p1[-4] = 2.4; // ouch! Another undetected error double* p2 = new double[100]; *p2 = 7.3; // ok p2[17] = 9.4; // ok p2[-4] = 2.4; // ouch! Undetected error • Fortunately, we have ways of avoiding such errors Stroustrup/Programming/2024/Chapter15 16 7.3 8.2 7.3 p1: p2:
  • 16. Access • A pointer does not know the number of elements that it's pointing to double* p1 = new double; double* p2 = new double[100]; p1[17] = 9.4; // error (obviously) p1 = p2; // assign the value of p2 to p1 p1[17] = 9.4; // now ok: p1 now points to the array of 100 doubles Stroustrup/Programming/2024/Chapter15 17 p1: p2: p1: (after the assignment) [0]: [99]:
  • 17. Access • A pointer does know the type of the object that it’s pointing to int* pi1 = new int(7); int* pi2 = pi1; // ok: pi2 points to the same object as pi1 double* pd = pi1; // error: can’t assign an int* to a double* char* pc = pi1; // error: can’t assign an int* to a char* • There are no implicit conversions between a pointer to one value type to a pointer to another value type • However, there are implicit conversions between value types: *pc = 8; // ok: we can assign an int to a char *pc = *pi1; // ok: we can assign an int to a char Stroustrup/Programming/2024/Chapter15 18 7 7 pi1: pc:
  • 18. The null pointer • Sometimes, we need to say “this pointer doesn’t point to anything just now” double* p = nullptr; // … If (p!=nullptr) // p points to something *p = 7; else *p = 9; // No! never do this, p doesn’t point to anything • More concisely, we can leave out the !=nullptr If (p) // p points to something, aka “p is valid’’ *p = 7; • nullptr is commonly used to indicate • End of a linked list • No pointer value available just now • No object to return a pointer to Stroustrup/Programming/2024/Chapter15 20
  • 19. A problem: memory leak double* calc(int result_size, int max) { double* p = new double[max]; // allocate max doubles on free store double* result = new double[result_size]; // … use p to calculate results to be put in result … return result; } double* r = calc(200,100); // oops! • We “forgot” to give the memory allocated by new back to the free store • That doesn’t happen automatically (“no garbage collection”) • Lack of de-allocation (usually called “memory leaks”) can be a serious problem in real-world programs Stroustrup/Programming/2024/Chapter15 21
  • 20. We can give memory back to the free store: detete double* calc1(int result_size, int max) { double* tmp = new double[max]; // allocate max doubles on free store double* result = new double[result_size]; // … use tmp to calculate results to be put in result … delete[] tmp; // return the memory pointed to by tmp to the free store return result; } double* r = calc1(200,100); // oops! // … use r … delete[ ] r; // return the memory pointed to by r to the free store Stroustrup/Programming/2024/Chapter15 22
  • 21. Memory leaks – resource leaks • A program that needs to run “forever” can’t afford any memory leaks • An operating system is an example of a program that “runs forever” • If a function leaks 8 bytes every time it is called, how many days can it run before it has leaked/lost a megabyte? • Trick question: not enough data to answer, but about 130,000 calls • All memory is returned to the system at the end of the program • If you run using an operating system (Windows, Unix, whatever) • Program that runs to completion with predictable memory usage may leak without causing problems • i.e., memory leaks aren’t “good/bad” but they can be a major problem in specific circumstances • Memory leaks is a major real-world problem • Memory leaks is just a special case of resource leaks • E.g., files, locks, sockets Stroustrup/Programming/2024/Chapter15 23
  • 22. Memory leaks • Another way to get a memory leak void f() { double* p = new double[27]; // … p = new double[42]; // … delete[] p; } // 1st array (of 27 doubles) leaked Stroustrup/Programming/2024/Chapter15 24 p: 2nd value 1st value
  • 23. Memory leaks •How do we systematically and simply avoid memory leaks? • Use resource handles • Use vector, etc. • don't mess directly with new and delete • Or use a garbage collector • A garbage collector is a program the keeps track of all of your allocations and returns unused free-store allocated memory to the free store • Not common in C++ • not covered in this course; see http://www.stroustrup.com/C++.html • Unfortunately, a garbage collector doesn’t prevent all resource leaks • Only memory leaks Stroustrup/Programming/2024/Chapter15 25
  • 24. A problem: memory leak void f(int x) { Vector v(x); // define a Vector (which allocates x doubles on the free store) // … use v … // give the memory allocated by v back to the free store // but how? (Vector's elem data member is private) } Stroustrup/Programming/2024/Chapter15 26
  • 25. Vector (destructor) // a very simplified Vector of doubles: class Vector { int sz; // the size double* elem; // a pointer to the elements public: Vector(int s) :sz(s), elem(new double[s]) { } // constructor: allocates/acquires memory ~Vector() { delete[ ] elem; } // destructor: de- allocates/releases memory // … }; • Note: this is an example of a general and important technique: • acquire resources in a constructor • release them in the destructor • Examples of resources: memory, files, locks, threads, sockets Stroustrup/Programming/2024/Chapter15 27
  • 26. Implicitly give memory back to the free store Vector<double> calc2(int result_size, int max) { Vector<double> tmp(max); // allocate max doubles on free store Vector<double> result(result_size); // … use tmp to calculate results to be put in result … return result; } // tmp destroyed upon return void user() { // … auto res = calc2(200,100); // oops! // … use r … } // res destroyed upon return Stroustrup/Programming/2024/Chapter15 28 Simpler and probably more efficient than using new and delete explicitly (yes, we can avoid copying a result v - Next lecture)
  • 27. Free store summary • Allocate using new • New allocates an object on the free store, sometimes initializes it, and returns a pointer to it • int* pi = new int; // default initialization (none for int) • char* pc = new char('a'); // explicit initialization • double* pd = new double[10]; // allocation of (uninitialized) array • New throws a bad_alloc exception if it can't allocate (out of memory) • Deallocate using delete and delete[ ] • delete and delete[ ] return the memory of an object allocated by new to the free store so that the free store can use it for new allocations • delete pi; // deallocate an individual object • delete pc; // deallocate an individual object • delete[ ] pd; // deallocate an array • Delete of a zero-valued pointer ("the null pointer") does nothing Stroustrup/Programming/2024/Chapter15 29
  • 28. Avoid “naked new” and “naked delete” • Manual resource allocation and deallocation is error-prone • We forget to hand resources back (Ask any librarian) • We use pointers after the memory they point to has been deleted • Use of “raw pointers” to manage memory leads to overuse of pointers • Using vector leads to simpler code • Compare calc1() and calc2() • See the following lectures and chapters Stroustrup/Programming/2024/Chapter15 30
  • 29. Generated destructors • If a member of a class has a destructor, then that destructor will be called when the object containing the member is destroyed. struct Customer { string name; vector<string> addresses; // ... }; void some_fct() { Customer fred { "Fred", {"17 Oak St.", "232 Rock Ave."}}; // ... use fred ... } • That saves us a lot of work Stroustrup/Programming/2024/Chapter15 31
  • 30. Virtual destructors • Destructors work correctly in class hierarchies • Provided you declare the destructor virtual Shape* fct() { Text tt {Point{200,200},"Anya"}; // local Text variable // ... return new Text{Point{100,100},"Courtney"}; // Text object on the free store } void user() { Shape* q = fct(); // ... use the Shape without caring exactly which kind of shape it is ... delete q; // Shape’s destructor is virtual so Text::~Text() is called if *q is a Text Stroustrup/Programming/2024/Chapter15 32
  • 31. But, what about “no naked deletes”? • Use “resource-manegement” pointers () unique_ptr<Shape> fct() { Text tt {Point{200,200},"Annemarie"}; // local Text variable // ... return make_unique<Text>(Point{100,100},"Nicholas"); // Text object on the free store } void user() { unique_ptr<Shape> q = fct(); // ... use the Shape without caring exactly which kind of shape it is ... } • Equivalent to the previous example, but simpler Stroustrup/Programming/2024/Chapter15 33
  • 32. Access to elements • But our Vector doesn’t have access operations • So, let’s add very simple ones class Vector { // a very simplified vector of doubles public: Vector(int s) :sz{s}, elem{new double[s]} { /* ... */ } // constructor ~Vector() { delete[] elem; } // destructor int size() const { return sz; } // the current size double get(int n) const { return elem[n]; } // access: read void set(int n, double v) { elem[n]=v; } // access: write private: int sz; // the size double* elem; // a pointer to the elements }; Stroustrup/Programming/2024/Chapter15 34
  • 33. Access to elements • Not very elegant • But it’ll do for now Vector v(5); for (int i=0; i<v.size(); ++i) { v.set(i,1.1*i); cout << "v[" << i << "]==" << v.get(i) << 'n'; } Stroustrup/Programming/2024/Chapter15 35
  • 34. Reminder •Why look at the Vector implementation? • To see how the standard library vector really works • To introduce basic concepts and language features • Free store (heap) • Copying • Dynamically growing data structures • To see how to directly deal with memory • To introduce the techniques and concepts we need to understand C • Including the dangerous ones (and see how to avoid those in C++) • To demonstrate class design techniques • To see examples of “neat” code and good design Stroustrup/Programming/2024/Chapter15 36
  • 35. Next lecture • We’ll see how we can change our Vector’s implementation to better allow for changes in the number of elements. Then we’ll modify Vector to take elements of an arbitrary type and add range checking. That’ll imply looking at templates and revisiting exceptions. Stroustrup/Programming/2024/Chapter15 37