CppAD: A C++ Algorithmic Differentiation Package
20130918
|
00001 /* $Id$ */ 00002 # ifndef CPPAD_TRACK_NEW_DEL_INCLUDED 00003 # define CPPAD_TRACK_NEW_DEL_INCLUDED 00004 00005 /* -------------------------------------------------------------------------- 00006 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-11 Bradley M. Bell 00007 00008 CppAD is distributed under multiple licenses. This distribution is under 00009 the terms of the 00010 Eclipse Public License Version 1.0. 00011 00012 A copy of this license is included in the COPYING file of this distribution. 00013 Please visit http://www.coin-or.org/CppAD/ for information on other licenses. 00014 -------------------------------------------------------------------------- */ 00015 /* 00016 $begin TrackNewDel$$ 00017 $spell 00018 cppad.hpp 00019 Cpp 00020 newptr 00021 Vec 00022 oldptr 00023 newlen 00024 ncopy 00025 const 00026 $$ 00027 00028 $section Routines That Track Use of New and Delete$$ 00029 $index new, track$$ 00030 $index delete, track$$ 00031 $index track, new and delete$$ 00032 $index memory, track$$ 00033 00034 $head Deprecated$$ 00035 $index deprecated, track memory$$ 00036 All these routines have been deprecated. 00037 You should use the $cref thread_alloc$$ memory allocator instead 00038 (which works better in both a single thread and 00039 properly in multi-threading environment). 00040 00041 $head Syntax$$ 00042 $codei%# include <cppad/track_new_del.hpp> 00043 %$$ 00044 $icode%newptr% = TrackNewVec(%file%, %line%, %newlen%, %oldptr%) 00045 %$$ 00046 $codei%TrackDelVec(%file%, %line%, %oldptr%) 00047 %$$ 00048 $icode%newptr% = TrackExtend(%file%, %line%, %newlen%, %ncopy%, %oldptr%) 00049 %$$ 00050 $icode%count% = TrackCount(%file%, %line%)%$$ 00051 00052 00053 $head Purpose$$ 00054 These routines 00055 aid in the use of $code new[]$$ and $code delete[]$$ 00056 during the execution of a C++ program. 00057 00058 $head Include$$ 00059 The file $code cppad/track_new_del.hpp$$ is included by 00060 $code cppad/cppad.hpp$$ 00061 but it can also be included separately with out the rest of the 00062 CppAD include files. 00063 00064 00065 $head file$$ 00066 The argument $icode file$$ has prototype 00067 $codei% 00068 const char *%file% 00069 %$$ 00070 It should be the source code file name 00071 where the call to $code TrackNew$$ is located. 00072 The best way to accomplish this is the use the preprocessor symbol 00073 $code __FILE__$$ for this argument. 00074 00075 $head line$$ 00076 The argument $icode line$$ has prototype 00077 $codei% 00078 int %line% 00079 %$$ 00080 It should be the source code file line number 00081 where the call to $code TrackNew$$ is located. 00082 The best way to accomplish this is the use the preprocessor symbol 00083 $code __LINE__$$ for this argument. 00084 00085 $head oldptr$$ 00086 The argument $icode oldptr$$ has prototype 00087 $codei% 00088 %Type% *%oldptr% 00089 %$$ 00090 This argument is used to identify the type $icode Type$$. 00091 00092 $head newlen$$ 00093 The argument $icode newlen$$ has prototype 00094 $codei% 00095 size_t %newlen% 00096 %$$ 00097 00098 $head head newptr$$ 00099 The return value $icode newptr$$ has prototype 00100 $codei% 00101 %Type% *%newptr% 00102 %$$ 00103 It points to the newly allocated vector of objects 00104 that were allocated using 00105 $codei% 00106 new Type[%newlen%] 00107 %$$ 00108 00109 $head ncopy$$ 00110 The argument $icode ncopy$$ has prototype 00111 $codei% 00112 size_t %ncopy% 00113 %$$ 00114 This specifies the number of elements that are copied from 00115 the old array to the new array. 00116 The value of $icode ncopy$$ 00117 must be less than or equal $icode newlen$$. 00118 00119 $head TrackNewVec$$ 00120 $index TrackNewVec$$ 00121 $index NDEBUG$$ 00122 If $code NDEBUG$$ is defined, this routine only sets 00123 $codei% 00124 %newptr% = %Type% new[%newlen%] 00125 %$$ 00126 The value of $icode oldptr$$ does not matter 00127 (except that it is used to identify $icode Type$$). 00128 If $code NDEBUG$$ is not defined, $code TrackNewVec$$ also 00129 tracks the this memory allocation. 00130 In this case, if memory cannot be allocated 00131 $cref ErrorHandler$$ is used to generate a message 00132 stating that there was not sufficient memory. 00133 00134 $subhead Macro$$ 00135 $index CPPAD_TRACK_NEW_VEC$$ 00136 The preprocessor macro call 00137 $codei% 00138 CPPAD_TRACK_NEW_VEC(%newlen%, %oldptr%) 00139 %$$ 00140 expands to 00141 $codei% 00142 CppAD::TrackNewVec(__FILE__, __LINE__, %newlen%, %oldptr%) 00143 %$$ 00144 00145 $subhead Previously Deprecated$$ 00146 $index CppADTrackNewVec$$ 00147 The preprocessor macro $code CppADTrackNewVec$$ is the 00148 same as $code CPPAD_TRACK_NEW_VEC$$ and was previously deprecated. 00149 00150 $head TrackDelVec$$ 00151 $index TrackDelVec$$ 00152 This routine is used to a vector of objects 00153 that have been allocated using $code TrackNew$$ or $code TrackExtend$$. 00154 If $code NDEBUG$$ is defined, this routine only frees memory with 00155 $codei% 00156 delete [] %oldptr% 00157 %$$ 00158 If $code NDEBUG$$ is not defined, $code TrackDelete$$ also checks that 00159 $icode oldptr$$ was allocated by $code TrackNew$$ or $code TrackExtend$$ 00160 and has not yet been freed. 00161 If this is not the case, 00162 $cref ErrorHandler$$ is used to generate an error message. 00163 00164 $subhead Macro$$ 00165 $index CPPAD_TRACK_DEL_VEC$$ 00166 The preprocessor macro call 00167 $codei% 00168 CPPAD_TRACK_DEL_VEC(%oldptr%) 00169 %$$ 00170 expands to 00171 $codei% 00172 CppAD::TrackDelVec(__FILE__, __LINE__, %oldptr%) 00173 %$$ 00174 00175 $subhead Previously Deprecated$$ 00176 $index CppADTrackDelVec$$ 00177 The preprocessor macro $code CppADTrackDelVec$$ is the 00178 same as $code CPPAD_TRACK_DEL_VEC$$ was previously deprecated. 00179 00180 $head TrackExtend$$ 00181 $index TrackExtend$$ 00182 This routine is used to 00183 allocate a new vector (using $code TrackNewVec$$), 00184 copy $icode ncopy$$ elements from the old vector to the new vector. 00185 If $icode ncopy$$ is greater than zero, $icode oldptr$$ 00186 must have been allocated using $code TrackNewVec$$ or $code TrackExtend$$. 00187 In this case, the vector pointed to by $icode oldptr$$ 00188 must be have at least $icode ncopy$$ elements 00189 and it will be deleted (using $code TrackDelVec$$). 00190 Note that the dependence of $code TrackExtend$$ on $code NDEBUG$$ 00191 is indirectly through the routines $code TrackNewVec$$ and 00192 $code TrackDelVec$$. 00193 00194 $subhead Macro$$ 00195 $index CPPAD_TRACK_EXTEND$$ 00196 The preprocessor macro call 00197 $codei% 00198 CPPAD_TRACK_EXTEND(%newlen%, %ncopy%, %oldptr%) 00199 %$$ 00200 expands to 00201 $codei% 00202 CppAD::TrackExtend(__FILE__, __LINE__, %newlen%, %ncopy%, %oldptr%) 00203 %$$ 00204 00205 $subhead Previously Deprecated$$ 00206 $index CppADTrackExtend$$ 00207 The preprocessor macro $code CppADTrackExtend$$ is the 00208 same as $code CPPAD_TRACK_EXTEND$$ and was previously deprecated. 00209 00210 $head TrackCount$$ 00211 $index TrackCount$$ 00212 The return value $icode count$$ has prototype 00213 $codei% 00214 size_t %count% 00215 %$$ 00216 If $code NDEBUG$$ is defined, $icode count$$ will be zero. 00217 Otherwise, it will be 00218 the number of vectors that 00219 have been allocated 00220 (by $code TrackNewVec$$ or $code TrackExtend$$) 00221 and not yet freed 00222 (by $code TrackDelete$$). 00223 00224 $subhead Macro$$ 00225 $index CPPAD_TRACK_COUNT$$ 00226 The preprocessor macro call 00227 $codei% 00228 CPPAD_TRACK_COUNT() 00229 %$$ 00230 expands to 00231 $codei% 00232 CppAD::TrackCount(__FILE__, __LINE__) 00233 %$$ 00234 00235 $subhead Previously Deprecated$$ 00236 $index CppADTrackNewVec$$ 00237 The preprocessor macro $code CppADTrackCount$$ is the 00238 same as $code CPPAD_TRACK_COUNT$$ and was previously deprecated. 00239 00240 $head Multi-Threading$$ 00241 $index multi-threading, TrackCount$$ 00242 $index TrackCount, multi-threading$$ 00243 $index thread, multi TrackCount$$ 00244 These routines cannot be used $cref/in_parallel/ta_in_parallel/$$ 00245 execution mode. 00246 Use the $cref thread_alloc$$ routines instead. 00247 00248 $head Example$$ 00249 $children% 00250 test_more/track_new_del.cpp 00251 %$$ 00252 The file $cref TrackNewDel.cpp$$ 00253 contains an example and test of these functions. 00254 It returns true, if it succeeds, and false otherwise. 00255 00256 $end 00257 ------------------------------------------------------------------------------ 00258 */ 00259 # include <cppad/local/define.hpp> 00260 # include <cppad/local/cppad_assert.hpp> 00261 # include <cppad/thread_alloc.hpp> 00262 # include <sstream> 00263 # include <string> 00264 00265 # ifndef CPPAD_TRACK_DEBUG 00266 # define CPPAD_TRACK_DEBUG 0 00267 # endif 00268 00269 // ------------------------------------------------------------------------- 00270 # define CPPAD_TRACK_NEW_VEC(newlen, oldptr) \ 00271 CppAD::TrackNewVec(__FILE__, __LINE__, newlen, oldptr) 00272 00273 # define CPPAD_TRACK_DEL_VEC(oldptr) \ 00274 CppAD::TrackDelVec(__FILE__, __LINE__, oldptr) 00275 00276 # define CPPAD_TRACK_EXTEND(newlen, ncopy, oldptr) \ 00277 CppAD::TrackExtend(__FILE__, __LINE__, newlen, ncopy, oldptr) 00278 00279 # define CPPAD_TRACK_COUNT() \ 00280 CppAD::TrackCount(__FILE__, __LINE__) 00281 // ------------------------------------------------------------------------- 00282 # define CppADTrackNewVec CPPAD_TRACK_NEW_VEC 00283 # define CppADTrackDelVec CPPAD_TRACK_DEL_VEC 00284 # define CppADTrackExtend CPPAD_TRACK_EXTEND 00285 # define CppADTrackCount CPPAD_TRACK_COUNT 00286 // ------------------------------------------------------------------------- 00287 namespace CppAD { // Begin CppAD namespace 00288 00289 // TrackElement ------------------------------------------------------------ 00290 class TrackElement { 00291 00292 public: 00293 std::string file; // corresponding file name 00294 int line; // corresponding line number 00295 void *ptr; // value returned by TrackNew 00296 TrackElement *next; // next element in linked list 00297 00298 // default contructor (used to initialize root) 00299 TrackElement(void) 00300 : file(""), line(0), ptr(CPPAD_NULL), next(CPPAD_NULL) 00301 { } 00302 00303 TrackElement(const char *f, int l, void *p) 00304 : file(f), line(l), ptr(p), next(CPPAD_NULL) 00305 { CPPAD_ASSERT_UNKNOWN( p != CPPAD_NULL); 00306 } 00307 00308 // There is only one tracking list and it starts it here 00309 static TrackElement *Root(void) 00310 { CPPAD_ASSERT_UNKNOWN( ! thread_alloc::in_parallel() ); 00311 static TrackElement root; 00312 return &root; 00313 } 00314 00315 // Print one tracking element 00316 static void Print(TrackElement* E) 00317 { 00318 CPPAD_ASSERT_UNKNOWN( ! thread_alloc::in_parallel() ); 00319 using std::cout; 00320 cout << "E = " << E; 00321 cout << ", E->next = " << E->next; 00322 cout << ", E->ptr = " << E->ptr; 00323 cout << ", E->line = " << E->line; 00324 cout << ", E->file = " << E->file; 00325 cout << std::endl; 00326 } 00327 00328 // Print the linked list for a thread 00329 static void Print(void) 00330 { 00331 CPPAD_ASSERT_UNKNOWN( ! thread_alloc::in_parallel() ); 00332 using std::cout; 00333 using std::endl; 00334 TrackElement *E = Root(); 00335 // convert int(size_t) to avoid warning on _MSC_VER systems 00336 cout << "Begin Track List" << endl; 00337 while( E->next != CPPAD_NULL ) 00338 { E = E->next; 00339 Print(E); 00340 } 00341 cout << "End Track List:" << endl; 00342 cout << endl; 00343 } 00344 }; 00345 00346 00347 // TrackError ---------------------------------------------------------------- 00348 inline void TrackError( 00349 const char *routine, 00350 const char *file, 00351 int line, 00352 const char *msg ) 00353 { 00354 CPPAD_ASSERT_UNKNOWN( ! thread_alloc::in_parallel() ); 00355 std::ostringstream buf; 00356 buf << routine 00357 << ": at line " 00358 << line 00359 << " in file " 00360 << file 00361 << std::endl 00362 << msg; 00363 std::string str = buf.str(); 00364 size_t n = str.size(); 00365 size_t i; 00366 char *message = new char[n + 1]; 00367 for(i = 0; i < n; i++) 00368 message[i] = str[i]; 00369 message[n] = '\0'; 00370 CPPAD_ASSERT_KNOWN( false , message); 00371 } 00372 00373 // TrackNewVec --------------------------------------------------------------- 00374 # ifdef NDEBUG 00375 template <class Type> 00376 inline Type *TrackNewVec( 00377 const char *file, int line, size_t len, Type * /* oldptr */ ) 00378 { 00379 # if CPPAD_TRACK_DEBUG 00380 static bool first = true; 00381 if( first ) 00382 { std::cout << "NDEBUG is defined for TrackNewVec" << std::endl; 00383 first = false; 00384 } 00385 # endif 00386 return (new Type[len]); 00387 } 00388 00389 # else 00390 00391 template <class Type> 00392 Type *TrackNewVec( 00393 const char *file , 00394 int line , 00395 size_t len , 00396 Type * /* oldptr */ ) 00397 { 00398 CPPAD_ASSERT_KNOWN( 00399 ! thread_alloc::in_parallel() , 00400 "attempt to use TrackNewVec in parallel execution mode." 00401 ); 00402 // try to allocate the new memrory 00403 Type *newptr = CPPAD_NULL; 00404 try 00405 { newptr = new Type[len]; 00406 } 00407 catch(...) 00408 { TrackError("TrackNewVec", file, line, 00409 "Cannot allocate sufficient memory" 00410 ); 00411 } 00412 // create tracking element 00413 void *vptr = static_cast<void *>(newptr); 00414 TrackElement *E = new TrackElement(file, line, vptr); 00415 00416 // get the root 00417 TrackElement *root = TrackElement::Root(); 00418 00419 // put this elemenent at the front of linked list 00420 E->next = root->next; 00421 root->next = E; 00422 00423 # if CPPAD_TRACK_DEBUG 00424 std::cout << "TrackNewVec: "; 00425 TrackElement::Print(E); 00426 # endif 00427 00428 return newptr; 00429 } 00430 00431 # endif 00432 00433 // TrackDelVec -------------------------------------------------------------- 00434 # ifdef NDEBUG 00435 template <class Type> 00436 inline void TrackDelVec(const char *file, int line, Type *oldptr) 00437 { 00438 # if CPPAD_TRACK_DEBUG 00439 static bool first = true; 00440 if( first ) 00441 { std::cout << "NDEBUG is defined in TrackDelVec" << std::endl; 00442 first = false; 00443 } 00444 # endif 00445 delete [] oldptr; 00446 } 00447 00448 # else 00449 00450 template <class Type> 00451 void TrackDelVec( 00452 const char *file , 00453 int line , 00454 Type *oldptr ) 00455 { 00456 CPPAD_ASSERT_KNOWN( 00457 ! thread_alloc::in_parallel() , 00458 "attempt to use TrackDelVec in parallel execution mode." 00459 ); 00460 TrackElement *P; 00461 TrackElement *E; 00462 00463 // search list for pointer 00464 P = TrackElement::Root(); 00465 E = P->next; 00466 void *vptr = static_cast<void *>(oldptr); 00467 while(E != CPPAD_NULL && E->ptr != vptr) 00468 { P = E; 00469 E = E->next; 00470 } 00471 00472 // check if pointer was not in list 00473 if( E == CPPAD_NULL || E->ptr != vptr ) TrackError( 00474 "TrackDelVec", file, line, 00475 "Invalid value for the argument oldptr.\n" 00476 "Possible linking of debug and NDEBUG compliations of CppAD." 00477 ); 00478 00479 # if CPPAD_TRACK_DEBUG 00480 std::cout << "TrackDelVec: "; 00481 TrackElement::Print(E); 00482 # endif 00483 00484 // remove tracking element from list 00485 P->next = E->next; 00486 00487 // delete allocated pointer 00488 delete [] oldptr; 00489 00490 // delete tracking element 00491 delete E; 00492 00493 return; 00494 } 00495 00496 # endif 00497 00498 // TrackExtend -------------------------------------------------------------- 00499 template <class Type> 00500 Type *TrackExtend( 00501 const char *file , 00502 int line , 00503 size_t newlen , 00504 size_t ncopy , 00505 Type *oldptr ) 00506 { 00507 CPPAD_ASSERT_KNOWN( 00508 ! thread_alloc::in_parallel() , 00509 "attempt to use TrackExtend in parallel execution mode." 00510 ); 00511 00512 # if CPPAD_TRACK_DEBUG 00513 using std::cout; 00514 cout << "TrackExtend: file = " << file; 00515 cout << ", line = " << line; 00516 cout << ", newlen = " << newlen; 00517 cout << ", ncopy = " << ncopy; 00518 cout << ", oldptr = " << oldptr; 00519 cout << std::endl; 00520 # endif 00521 CPPAD_ASSERT_KNOWN( 00522 ncopy <= newlen, 00523 "TrackExtend: ncopy is greater than newlen." 00524 ); 00525 00526 // allocate the new memrory 00527 Type *newptr = TrackNewVec(file, line, newlen, oldptr); 00528 00529 // copy the data 00530 size_t i; 00531 for(i = 0; i < ncopy; i++) 00532 newptr[i] = oldptr[i]; 00533 00534 // delete the old vector 00535 if( ncopy > 0 ) 00536 TrackDelVec(file, line, oldptr); 00537 00538 return newptr; 00539 } 00540 00541 // TrackCount -------------------------------------------------------------- 00542 inline size_t TrackCount(const char *file, int line) 00543 { 00544 CPPAD_ASSERT_KNOWN( 00545 ! thread_alloc::in_parallel() , 00546 "attempt to use TrackCount in parallel execution mode." 00547 ); 00548 size_t count = 0; 00549 TrackElement *E = TrackElement::Root(); 00550 while( E->next != CPPAD_NULL ) 00551 { ++count; 00552 E = E->next; 00553 } 00554 return count; 00555 } 00556 // --------------------------------------------------------------------------- 00557 00558 } // End CppAD namespace 00559 00560 // preprocessor symbols local to this file 00561 # undef CPPAD_TRACK_DEBUG 00562 00563 # endif