-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcpp_cheatsheet2.cpp
347 lines (280 loc) · 9.34 KB
/
cpp_cheatsheet2.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
/* written by Nick Shin - [email protected]
* the code found in this file is licensed under:
* - Unlicense - http://unlicense.org/
*
* this file is from https://github.com/nickshin/CheatSheets/
*
*
* this code will show the basic principles of:
* - templates
* - const-ness
* - dynamic memory
* - exceptions
*
*
* to compile:
* g++ cpp_cheatsheet2.cpp -o cpp_cheatsheet2
*
* to run:
* ./cpp_cheatsheet2
*
*
* best viewed in editor with tab stops set to 4
* NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
*/
#include <iostream> // cout cerr
#include <cstdlib> // free
#include <string.h> // strdup strlen
#include <exception> // set_terminate set_unexpected
#include <new> // set_new_handler
using namespace std;
// ----------------------------------------
template <class T>
T templateFunction( T a, T b ) {
T result;
result = ( a > b ) ? a : b;
return result;
// all of the above can also be shorten to this:
// return ( a > b ) ? a : b;
}
// ----------------------------------------
template <class T>
class templateClass
{
private:
T a, b;
public:
templateClass( T first, T second ) { a = first; b = second; }
T getMax() { return ( a > b ) ? a : b; }
T getMin();
};
// when functions are defined outside of the class template
template <class T>
T templateClass<T>::getMin()
{
return ( a < b ) ? a : b;
}
// template specialization: think of this as overriding a specific template type
template <>
class templateClass <char>
{
private:
char c;
public:
templateClass( char arg ) { c = arg; }
char getUpper() {
if ( ( c >= 'a' ) && ( c <= 'z' ) )
c += 'A' - 'a';
return c;
}
};
// note: templates arguments are like parameters of a function...
// template < int, float >
// template < class T, double >
// template < class T, int, float, long, double >
// etc...
// ----------------------------------------
void
templateTest()
{
int i = 10, j =20, a, b;
a = templateFunction( i, j ); // compiler will figure this out
b = templateFunction<int>( 1, 2 ); // explicitly
cout << "*** template function\n";
cout << a << endl;
cout << b << endl;
cout << "\n*** template class\n";
templateClass<int> tci( 100, 200 );
cout << tci.getMax() << endl;
cout << tci.getMin() << endl;
cout << "\n*** template specialization\n";
templateClass<char> tcc( 'c' );
cout << tcc.getUpper() << endl;
}
// ----------------------------------------
class constTest
{
private:
char* x;
public:
int y;
mutable int z;
constTest( const char* arg ) { x = strdup( arg ); y = 1; z = 2; }
~constTest() { if ( x ) free( x ); }
void doNothing1() { };
void doNothing2() const { };
const char* const MemberFunction() const {
// see end of const_ness() for a note on this
// doNothing1(); // will not compile
doNothing2(); // will compile
// y = 10; // will not compile
z = 20; // will compile due to mutable keyword
return x;
}
};
void
const_ness()
{
cout << "\n*** const-ness\n";
// basically, 'const' applies to whatever is on its immediate left
// (other than if there is nothing there [i.e. at the begining],
// in which case it applies to whatever is its immediate right).
// for variable declaration and assigning this should be fairly straightforward.
// there are a few other important details to note.
// const_cast<> should only be used if the orignal variable is NOT const.
// for example:
const int x = 4; // x is const, it can't be modified
const int* const pX = &x; // can not modify x through the pX pointer
cout << x << endl; // prints "4"
int* pI = const_cast < int* > (pX); // explicitly cast pX as non-const
*pI = 3; // result is undefined
cout << x << endl; // compiler will use [ const int x = 4; ] for x here
int y = 5;
// pX was a one time assignment, so it cannot be changed to point to something else
// pX = &y; // will not compile
// here, pY will be able to point to another location.
// note the missing 2nd const as done with in pX.
const int* pY = &x;
pY = &y; // can not modify y through the pY pointer
// here, the first const will not allow this assignment even though y itself is not const
// *pY = 2; // will not compile
pI = const_cast < int* > (pY); // explicitly cast pY as non-const
*pI = 3; // valid assignment
cout << y << endl; // prints "3"
// const function, with the following:
// const char* const MemberFunction() const
//
// the second const means that the pointer returned is a const, so it
// cannot be changed to point to something else (this is like pX above).
//
// the first const means that nothing can be modified at what the pointer
// is pointing to (this is like x above).
//
// the last const, tells the compiler to check to make sure that none
// of the object's data will be modified and any other member functions
// invoked should also be declared as const.
const char* p1 = "hi there";
const constTest cT( p1 );
cout << cT.MemberFunction() << endl;
// mutable: allows data members to be modified even though the member
// is part of an object declared as const.
cout << "y: " << cT.y << " z: " << cT.z << endl;
// cT.y = 100; // will not compile
cT.z = 200; // will compile due to mutable keyword
cout << "y: " << cT.y << " z: " << cT.z << endl;
}
// ----------------------------------------
void
terminateCatch()
{
cerr << "Custom Exception Handler: terminate called\n";
}
void
unexpectedCatch()
{
cerr << "Custom Exception Handler: unexpected called\n";
}
void
noMemoryCatch()
{
cerr << "Custom Exception Handler: no memory called\n";
// here, the code can try to make more storage available
// and the new/new[] operators will be tried again.
//
// be aware, this will lead to an infinite loop if storage cannot be made available;
// in which case, handler must throw another exception or terminate the program.
throw bad_alloc();
// exit(1);
}
// NOTE: the XXX notations here on denotes alternative lines of codes to
// try out to see the different behaviours/response in using them.
// exception specifications: force a guarantee that a function (directly
// and indirectly) that only certain exceptions will be thrown within it;
// otherwise, terminate the program.
//
// void throwAnException(); // all exception types allowed
// void throwAnException() throw(); // no exceptions thrown - or terminate program
// void throwAnException() throw(float); // only floats thrown - or terminate program
// void throwAnException() throw(constTest); // only classes constTest thrown - or terminate program
// void throwAnException() throw(int, char); // only ints and chars thrown - or terminate program
//
// unexpected handler can still throw exceptions, but program will still terminate
// XXX: try one or the other to see how unexpected exception types are handled
void
throwAnException()
//throwAnException() throw(char) // will terminate the program
{
throw 1;
}
void
exceptionTest()
{
int breakme = 1000000000;
// exception handler
try {
// dynamic memory
cout << "\n*** dynamic memory\n";
int size = 1024;
// size *= breakme; // XXX: see what happends if this is used
int *p = new int[size];
cout << "alloc successful\n";
delete[] p; // note: an array
p = new int;
cout << "another alloc successful\n";
delete p; // note: a single element
// nested exception handler
cout << "\n*** exception\n";
try {
// XXX: try commenting one or the other to see the catch types
// throw 20; // throw an exception manually
throw 'x'; // throw an exception manually
}
catch( int ) { cerr << "Exception 1: caught int\n"; }
catch( char ) { cerr << "Exception 1: caught char\n"; }
cout << "end of inner try-catch\n";
}
// a bad memory alloc can be caught in the following way:
// from the most specific exception type... to the most general...
// XXX: try commenting out the following catches one at a time
catch( bad_alloc& ) { cerr << "Exception 2: Error allocating memory\n"; }
catch( exception& e ) { cerr << "Exception 2: " << e.what() << endl; }
catch( ... ) { cerr << "Exception 2: catch all\n"; }
cout << "end of outer try-catch\n\n";
// XXX: "no throw" exception, see what happens with the other line of code...
int *pp = new (nothrow) int[breakme];
// int *pp = new int[breakme]; // will terminate the program
if ( pp ) {
cout << "nothrow 1: alloc successful\n\n";
delete[] pp;
} else cerr << "nothrow 1: Error allocating memory\n\n";
// trying this again, but with a custom handler
set_new_handler(noMemoryCatch);
try {
// with nothrow
pp = new (nothrow) int[breakme]; // note how custom handler is still called
if ( pp ) {
cout << "nothrow 2: alloc successful\n\n";
delete[] pp;
} else cerr << "nothrow 2: Error allocating memory\n\n";
// without nothrow - but inside try-catch
pp = new int[breakme]; // now, will NOT terminate the program
cout << "with throw 2: alloc successful\n\n";
delete[] pp;
}
catch( exception& e ) { cerr << "Exception: " << e.what() << endl << endl; }
// more custom handlers
set_terminate(terminateCatch);
set_unexpected(unexpectedCatch);
try { throwAnException(); }
catch( int ) { cerr << "Exception 3: caught int\n"; }
}
// ----------------------------------------
int
main()
{
templateTest();
const_ness();
exceptionTest();
cout << "\ntests all done!\n";
return 0;
}