The ||
and &&
operators short-circuit
Operator | LHS | Result |
---|---|---|
` | ` | |
&& |
0 | RHS not evaluated |
#include <iostream>
using namespace std;
int one( )
{
cout << "in one" << endl;
return 1;
}
int zero( )
{
cout << "in zero" << endl;
return 0;
}
int main( )
{
// Math operators
cout << "0 * one( ) = " << endl;
cout << ( 0 * one( ) ) << endl << endl;
// Logical operators
cout << "1 || one( ) = " << endl;
cout << ( 1 || one( ) ) << endl << endl;
cout << "one( ) || one( ) = " << endl;
cout << ( one( ) || one( ) ) << endl << endl;
cout << "0 && one( ) = " << endl;
cout << ( 0 && one( ) ) << endl << endl;
cout << "zero( ) && one( ) = " << endl;
cout << ( zero( ) && one( ) ) << endl << endl;
// Bitwise operators
cout << "1 | one( ) = " << endl;
cout << ( 1 | one( ) ) << endl << endl;
cout << "one( ) | one( ) = " << endl;
cout << ( one( ) | one( ) ) << endl << endl;
cout << "0 & one( ) = " << endl;
cout << ( 0 & one( ) ) << endl << endl;
cout << "zero( ) & one( ) = " << endl;
cout << ( zero( ) & one( ) ) << endl;
}
g++ operations.cpp -o operations
operations
0*one( ) =
in one
0
1 || one( ) =
1
one( ) || one( ) =
in one
1
0 && one( ) =
0
zero( ) && one( ) =
in zero
0
1 | one( ) =
in one
1
one( ) | one( ) =
in one
in one
1
0 & one( ) =
in one
0
zero( ) & one( ) =
in zero
in one
0
8
An object is a piece of data in memory. An object lives at an address in memory. You can use an object during its lifetime. Lifetimes are managed according to storage duration. Three options in C++:
- Global (Static)
- Lives for the whole program.
- Managed by the compiler
- Local (Automatic)
- Lives during the execution of its local block.
- Managed by you
- Dynamic
- You control the lifetime!
Defined:
- Outside of a function/class definition,
- As
static
within a function, or - As
static
within a class definition
Created before the program begins and live until the very end
Compiler reserves space for these
Lives inside a block { curly braces }
Usually a function or loop body, but also just a plain block
Initialized when the declaration is run
Dies when the block is finished
Called dynamic because:
- Its size (or number) is determined at runtime.
- When to create and destroy (or delete) it is determined at runtime.
The programmer decides how big a dynamic variable is, when it is created, and when it is destroyed
Created dynamic variables using new
This creates a new object in memory, and returns a pointer to that object.
int f1( )
{
int *p = new int;
}
int f2( )
{
int *p = new int( 5 );
}
In f1, the intial value is undefined
In f2, initializer syntax has been used to assign an intial value
Destroy dynamic variables using delete
Releases the claim on the space previously used by the int
Space can be recycled later by new
int *p = new int;
// Do something with p or the
// int that it points to.
:
delete p;
To force an error, many programmers set the pointer to nullptr
or 0
after delete
int *p = new int;
// Do something with p or the
// int that it points to.
:
delete p;
p = nullptr;
cout << *p;
You can only delete a dynamic variable once, and if you attempt to delete something that's already been deleted, you'll usually but not always crash.
Deleting a null pointer is ignored, so set the pointer to nullptr
int *p = new int;
// Do something with p or the
// int that it points to.
:
delete p;
p = nullptr;
delete p;
Ordinary objects can be destroyed by delete
, but only if they were created by new
int i = 0;
int *p = &i;
delete p;
Dynamic variables live until the programmer destroys them using delete
This is true even if you "forget" the pointer to the object
int main( )
{
int *p1 = new int( 1 );
int *p2 = new int( 2 );
p1 = p2;
}
There is no way to delete p1
Exiting the block causes the local objects p1
and p2
to vanish, but the dynamic object they point to remains.
Still have allocated dynamic objects but no means of reclaiming.
This is a memory leak.
- If you want to manage the lifetime of the variable yourself
- Not local, not global, but something in between
- Many parts of the code refer to an object, but only want one copy in memory
- Normaly, if many parts refer to the same object, those parts will be in different scopes
A separate region of memory used for dynamic storage
Each object has its own lifetime, independent of the others around it. No Stack Frames!
The new
and delete
operators allow us to interact with the heap
malloc()
andfree()
are C’s new and delete- The malloc and free functions also work with the heap, but they aren't generally used in C++ style programming.
A running program has an "address space", a collection of memory locations that are accessible to it
An address space is private to a running program - no other running program can access/modify it
It is possible through calls to the operating system to be shared with another running program
There are typically five parts, called segments, in an address space
Address MAX
Stack (grows down) |
THE BIG VOID |
Heap (grows up) |
Globals (Fixed size) |
Text (The program) |
Address 0
The code comprising a compiled program goes in the text segment
It is at a very low address, but typically not at address zero
Immediately above the text section, the compilter allocates space for any global variables, and intializes them, when necessary
When dynamic variables are allocated with new, they come from the heap, which grows upwards
When functions are called, stack frames are created on the stack, which grows downward
Since we don't know how big either of these will get, we keep a big hole in between the two called THE BIG VOID
Most systems also reserve the first few thousand addresses starting at zero for another void
Global | Local | Dynamic | |
---|---|---|---|
Where in code? | Outside function | Inside function (block) or args | Anywhere you sue new |
When created | Beginning of program | Beginning of function (block) | You call new |
When destroyed | End of program | End of function (block) | You call delete |
Size | static | static | dynamic |
Location | Globals | Stack | Heap |
int main( )
{
int *p = new int( 100 ); // Always initialize variables
assert( p );
cout << *p << endl;
delete p;
p = nullptr;
}
Local variable int *p
goes on the stack
Dynamic memory new int( 100 )
goes on the heap
Access a dynamic variable using a pointer
Use an assert()
to catch null pointer before it causes a SEGFUALT
// Preferred
int *ptr = NULL;
// Also works
int *ptr = 0;
// Preferred
int *ptr = nullptr;
// Also works
int *ptr = 0;
// Compile error.
// NULL is undefined.
int *ptr = NULL;
int i = 42,
*p = &i;
delete p;
p = nullptr;
int i = 4,
*p = new int( 17 );
i = *p;
delete p;
p = nullptr;
No memory is leaked
int *p = new int( 100 ),
*q = p;
delete q;
q = nullptr;
cout << *p << endl;
Printed value is undefined
No memory is leaked
int *p = new int( 100 ),
*q = new int( 42 );
q = p;
delete q;
q = nullptr;
Probably 4 bytes, sizeof( int )
are leaked