Download presentation
Presentation is loading. Please wait.
Published bySimon Jones Modified over 9 years ago
1
1 Data Structures - CSCI 102 CS102 C++ Pointers & Dynamic Objects Prof Tejada
2
3 Data Structures - CSCI 102 Stack Variables When you create variables normally, they live on the stack and their lifetime is tied to their scope (the { }) int foo() { int x = 5; return x + 1; } The variable x is a stack variable Memory for x is created on the stack when foo() is called Memory for x is "freed" from the stack when foo() returns Not really "freed", the stack frame is popped C++ manages memory for stack variables for you. They are automatically created and destroyed. Stack allocation is mostly handled by the compiler The compiler generate machine code to push and pop the program stack
3
4 Data Structures - CSCI 102 Stack Variables Sometimes stack variables can be really inconvenient int* bar() { int x; cin >> x; // Let’s say x got 5 return &x; } int main() { int *ptr = bar(); cout << "*ptr = " << *ptr << endl; } This is a really bad idea because x lives on the stack and it will be destroyed when bar() returns We’ll be returning a pointer to unusable memory
4
Data Structures - CSCI 102 Stack Variables Sometimes stack variables can be really inconvenient int* bar() { int x; cin >> x; // Let’s say x got 5 return &x; } int main() { int *ptr = bar(); cout << "*ptr = " << *ptr << endl; } 5 stack bar() calls 0x05 main() ptr ?? x 0x00 0x00 0x00 0xbfffedb4 ? 0xbfffecd0 top of stack
5
Data Structures - CSCI 102 Stack Variables Sometimes stack variables can be really inconvenient int* bar() { int x; cin >> x; // Let’s say x got 5 return &x; } int main() { stack returned 0x05 0xbfffedb4 main() ptr 0xbf 0xff 0xec 0xd0 int *ptr = bar(); cout << "*ptr = " << *ptr << endl; } Why wouldn’t this print out 5? 6 0xbfffecd0 0x00 0x00 0x00 top of stack
6
Data Structures - CSCI 102 Stack Variables Sometimes stack variables can be really inconvenient int* bar() { int x; cin >> x; // Let’s say x got 5 return &x; } int main() { operator<<() calls ???? ? 0xbfffedb4 main() ptr 0xbf 0xff 0xec 0xd0 0xbfffecd0 int *ptr = bar(); cout << "*ptr = " << *ptr << endl; } Why wouldn’t this print out 5? Because that part of the program stack gets recycled! 7 top of stack stack
7
Sometimes stack variables can be really inconvenient 8 Data Structures - CSCI 102 Copyright © William C. Cheng Stack Variables int* bar() { int x; cin >> x; // Let’s say x got 5 return &x; } What if we want the pointer to x to stick around long after bar() has been called? What if we don’t want C++ to manage memory for us? Use dynamically allocated data structures to manage data ourselves
8
By default all variables go on the stack You MUST clean up after yourself! The heap is large pool of free memory in your C++ application that is used for dynamic variable allocation 9 Data Structures - CSCI 102 Copyright © William C. Cheng Heap Variables and the new Operator You must explicitly allocate variables on the heap The heap is not automatically memory managed for you like the stack is The C++ operator new can be used to dynamically create new variables on the heap When you use the new operator, you’re telling C++ that it should NOT manage memory for you
9
Since you’re dynamically creating variables on the fly, their location is not known in advance The new operator returns a pointer to the new memory it has allocated 10 Data Structures - CSCI 102 The new Operator Create a pointer to a new integer on the heap: int* x = new int; *x = 55; Or all in one statement: int* x = new int(55);
10
bar() calls main() ptr ?? 0xbfffedb4 ? 0xbfffecd0 x 0x08 0x04 0xb0 0x08 int *x = new int; cin >> *x; // Let’s say x got 5 return x; } int main() { int *ptr = bar();... } 11 Data Structures - CSCI 102 The new Operator Using a heap variable int* bar() { 0x804b008 0x00 0x00 0x00 0x05 heap stack top of stack
11
bar() calls main() ptr ?? x 0xbfffedb4 ? 0xbfffecd0 int *x = new int; cin >> *x; // Let’s say x got 5 return x; } int main() { int *ptr = bar();... } 12 Data Structures - CSCI 102 The new Operator Using a heap variable int* bar() { 0x804b008 0x00 0x00 0x00 0x05 heap stack top of stack
12
returned 0xbfffecd0 x 0x08 0x04 0xb0 0x08 top of stack int *x = new int; cin >> *x; // Let’s say x got 5 return x; } int main() { int *ptr = bar();... } 0xbfffedb4 main() ptr 0x08 0x04 0xb0 0x08 13 Data Structures - CSCI 102 The new Operator Using a heap variable int* bar() { 0x804b008 0x00 0x00 0x00 0x05 heap stack
13
returned 0xbfffecd0 x 0x08 0x04 0xb0 0x08 top of stack 0xbfffedb4 main() ptr int *x = new int; cin >> *x; // Let’s say x got 5 return x; } int main() { int *ptr = bar();... } 14 Data Structures - CSCI 102 The new Operator Using a heap variable int* bar() { 0x804b008 0x00 0x00 0x00 0x05 heap stack
14
Binky http://cslibrary.stanford.edu/104/ 15 Data Structures - CSCI 102 The new Operator
15
When you use the new operator, you’re telling C++ that you will manage your own memory 16 Data Structures - CSCI 102 The delete Operator If you use new to allocate memory like this: int* x = new int(55); Then later you must use delete to clean up the previously allocated memory like this: delete x;
16
The delete operator only marks heap memory as free to be used again, it does not actually destroy it! delete does NOT change where x is pointing 17 Data Structures - CSCI 102 The delete Operator If you use new to allocate memory like this: int* x = new int(55); cout << "X = " << *x << endl; delete x; //what will the following do? cout << "X = " << *x << endl; It’s a good idea to set pointers to NULL when you’re done using them NULL essentially says "this pointer points nowhere" delete x; x = NULL;
17
What if you start using new, but you forget to add the associated calls to delete? This is called a memory leak 18 Data Structures - CSCI 102 The delete Operator If you keep allocating memory from the heap using new and never use delete to clean up, you will eventually run out of memory! Not a big problem for small, short-lived applications, but a major problem for code that’s going to run for a long time This will eventually make your application crash
18
All memory allocated using new is eventually returned when your application terminates (whether you used delete on it or not) 19 Data Structures - CSCI 102 Other Notes on new and delete You can also use new to dynamically create arrays: int* values = new int[100]; Dynamic arrays can even be sized based on variables int size = 256; int* values = new int[size]; Deleting dynamic arrays looks slightly different delete []values;
19
From this point on, memory block starting at addr belongs to the user/application Memory Allocator is defined by its interface 40 Data Structures - CSCI 102 Memory Allocator new eventually will invoke malloc() delete eventually will invoke free() addr = malloc(size) - to allocate a contiguous block of memory of size bytes long From this point on, memory block starting at addr belongs to the memory allocator again Memory allocator must not touch it any more free(addr) - return memory block starting at addr to the memory allocator User/application must not touch it any more
20
Size of heap Data Structures - CSCI 102 Memory Allocator Initially, the memory allocator was given a large block of memory to manage In a real memory allocator, this is the entire heap space Memory Allocator Begining of heap It has a starting address and a size 41
21
42 Data Structures - CSCI 102 Memory Allocator Initially, the memory allocator was given a large block of memory to manage In a real memory allocator, this is the entire heap space Memory Allocator Begining of heap Return the address of the block to the user It has a starting address and a size User/application busy User Pointer When malloc(size) is called, the allocator finds a contiguous block of memory size bytes long, mark it busy/in-use
22
43 Data Structures - CSCI 102 Memory Allocator Initially, the memory allocator was given a large block of memory to manage In a real memory allocator, this is the entire heap space Memory Allocator Begining of heap memory It has a starting address and a size User/application free When free(addr) is called, the allocator makes the block free so it can be allocated later The block is merged with the rest of the free
23
User/application code can corrupt the memory allocation chain easily As you can see, one mistake in the memory allocator code and your blocks are all messed up 60 Data Structures - CSCI 102 Dynamic Memory Allocation The result can lead to segmentation faults Unfortunately, the corruption can stay hidden for a long time and eventually lead to a segmentation fault Memory corruption bugs are very difficult to squash
24
Now that we have a pointer member variable, how do our constructors change? 20 Data Structures - CSCI 102 The Point Class class Point { private: int x; int y; int* z; public: Point(); Point(int newx, int newy, int newz); };
25
What happens to the memory allocated by new when our class is destroyed? 21 Data Structures - CSCI 102 The Point Class Point::Point() { x = 0; y = 0; z = new int; *z = 0; } Point::Point(int newx, int newy, int newz) { x = newx; y = newy; z = new int(newz); }
26
22 Data Structures - CSCI 102 C++ Classes: Destructors A class’s destructor is called when: 1) a stack object goes out of scope 2) a heap object is freed from the heap (by delete) It can also be invoked directly (e.g., inside STL code, inside delete, inside delete[]) Destructor Can have one or none If class has no destructor, C++ will make one No return value Has the name ~ClassName() Why use it? Not necessary in simple cases Clean up resources that won’t go away automatically (e.g. stuff you used new to create)
27
23 Data Structures - CSCI 102 The Point Class Destructor class Point { private: int x; int y; int* z; public: Point(); Point(int newx, int newy, int newz); ~Point(); }; Point::~Point() { delete z; }
28
1) Memory block of sizeof(Foo) bytes allocated from heap and its address returned and assigned to ptr 24 Data Structures - CSCI 102 C++ Classes: Destructors Assume that you started with: Foo *ptr = new Foo(); delete ptr; What happens when you call: 1) Foo::~Foo() will be called 2) Memory block located at ptr will be deallocated Two things happens 2) Foo::Foo() called Two things happens
29
25 Data Structures - CSCI 102 C++ Classes: Destructors Assume that you started with: Two things Foo *ptr=new Foo[5]; delete[] ptr; What happens when you call: 1) Foo::~Foo() will be called 5 times, once for each array element 2) Memory block located at ptr will be deallocated (done only one time) for (int i=0; i < 5; i++) { Foo *p=&ptr[i]; p->~Foo(); //looks weird, but accurate! }
30
26 members? Data Structures - CSCI 102 Shallow vs. Deep Copy For all classes, C++ defines a basic capability to copy a class By default, class data is just copied member-by-member from one instance to another Point p1(100,100); Point p2 = p1; In the second statement, C++ essentially does this: p2.x = p1.x; p2.y = p1.y; This is called making a shallow copy A straight foward memory to memory copy: memcpy(&p2, &p1, sizeof(Point)); This may not be what you want! What happens if the Point class contains pointer
31
Let’s try this again: 27 Data Structures - CSCI 102 Shallow vs. Deep Copy Assume the class Point has three members: p2.x = p1.x; p2.y = p1.y; p2.z = p1.z; //this is pointer assignment! After the shallow copy, p2.z and p1.z are now pointing to the same integer in memory! Sometimes, this is exactly what you want Sometimes, this is not what you want Only you know which behavior you want
32
28 Data Structures - CSCI 102 Shallow vs. Deep Copy When our class contains pointers, we must force C++ to do a deep copy, if appropriate A deep copy is smart enough to copy the actual data, not just the variable values How do we make a deep copy? p2.x = p1.x; p2.y = p1.y; p2.z = new int(*(p1.z)); //makes a new pointer! After the deep copy, p1 and p2 have separate pointers The pointers are different p1.z != p2.z They point to two instances of same value in this example *(p1.z) == *(p2.z) But who is doing the deep copy?
33
29 an object! Data Structures - CSCI 102 The Copy Constructor When you declare an object, you can initialize it to another object like this: string original("Hello world!"); string my_copy(original); By default, a simple copy constructor is provided for you by the compiler It just blindly copies values from the original to the copy member by member (a shallow copy) Point original(12,30); Point my_copy(original); //this works too! Point another_copy = original; Using memcpy() Copy constructors are only called during creation of
34
Remember that when we pass something "by value" to a function, C++ makes a copy 30 Data Structures - CSCI 102 The Copy Constructor void foo(Point c) {...} The copy constructor is responsible for making copies of objects that get passed "by value" class Point { public: Point(const Point& original) { x = original.x; y = original.y; z = new int(*(original.z)); }}}} }; What does a copy constructor look like?
35
If the default member-by-member copying works, why would we define our own? 31 Data Structures - CSCI 102 The Copy Constructor If some data should not be copied e.g. You have a member variable that stores the time the object was created If you have pointers By default, the pointer itself will be copied (NOT the thing it’s pointing to!) You will end up with two pointers both pointing to the exact same value in memory! This is IMPORTANT Again, sometimes, this is exactly what you want; sometimes, this is not what you want. Only you know which behavior you want
36
So if copy constructors only take care of object creation, what about the ’=’? 32 Data Structures - CSCI 102 The ’=’ Operator Point c1(12,30); Point c2(0,0); //this doesn’t call the copy constructor c2 = c1; By default, this compiles and works, but what’s going on? The ’=’ does the same member-by-member copy, but via a different method (a shallow copy) Using the default ’=’ will have the exact same problems as the default copy constructor! Using memcpy()
37
So how can we make this work? 33 Data Structures - CSCI 102 The ’=’ Operator Point c1(12,30), c2(0,0); c2 = c1; Overload the assignment operator Things to consider Point& Point::operator=(const Point &other) Why does it return a Point&? It must be implemented as a member function Other notes It should end with: return *this;
38
34 Data Structures - CSCI 102 The ’=’ Operator Point& Point::operator=(const Point &other) { //what is the purpose of this if? if (this != &other) { x = other.x; y = other.y; z = new int(*(other.z)); } //what is the purpose of this return? return *this; }
39
Destructor Good C++ coding dictates that if you find that you have to create any of these for your class: 35 Data Structures - CSCI 102 The Rule of 3 Copy Constructor Assignment Operator (=) The things that force you to implement one of them (e.g. pointer member variables) affect all of them Then you should make sure you implement all three of them! You can get into big trouble if you have a destructor, but no copy constructor or = operator Unless you are extremely careful (and have a habit of never using automatic variable of this class)
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.