From b1a4b3a0471a8b59c1ad8857bc69db9d8e91df04 Mon Sep 17 00:00:00 2001 From: rich_sposato Date: Wed, 9 May 2007 00:57:06 +0000 Subject: [PATCH] Added CheckReturn facility to Loki. git-svn-id: svn://svn.code.sf.net/p/loki-lib/code/trunk@824 7ec92016-0320-0410-acc4-a06ded1c099a --- Loki.sln | 8 +- include/loki/CheckReturn.h | 96 ++++++++++++ test/CachedFactory/CachedFactory.vcproj | 4 +- test/CheckReturn/CheckReturn.dev | 69 +++++++++ test/CheckReturn/CheckReturn.vcproj | 198 ++++++++++++++++++++++++ test/CheckReturn/main.cpp | 155 +++++++++++++++++++ test/Function/Function.vcproj | 4 +- test/SmallObj/SmallObjBench.cpp | 2 - 8 files changed, 529 insertions(+), 7 deletions(-) create mode 100755 include/loki/CheckReturn.h create mode 100755 test/CheckReturn/CheckReturn.dev create mode 100755 test/CheckReturn/CheckReturn.vcproj create mode 100755 test/CheckReturn/main.cpp diff --git a/Loki.sln b/Loki.sln index 14f0ec7..d535415 100644 --- a/Loki.sln +++ b/Loki.sln @@ -1,6 +1,6 @@  Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual C++ Express 2005 +# Visual Studio 2005 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Library", "src\library.vcproj", "{CBDB8E7A-4286-4AE3-A190-BA33D7C53FF0}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Factory", "test\Factory\Factory.vcproj", "{925D5863-2F77-41B7-96F1-CC814762C40F}" @@ -57,6 +57,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Function", "test\Function\F EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CachedFactory", "test\CachedFactory\CachedFactory.vcproj", "{8D186AB4-E544-42D6-B192-1AE2C946875E}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CheckReturn", "test\CheckReturn\CheckReturn.vcproj", "{C0826A05-9143-4545-B5DE-811C188CB54E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -139,6 +141,10 @@ Global {8D186AB4-E544-42D6-B192-1AE2C946875E}.Debug|Win32.Build.0 = Debug|Win32 {8D186AB4-E544-42D6-B192-1AE2C946875E}.Release|Win32.ActiveCfg = Release|Win32 {8D186AB4-E544-42D6-B192-1AE2C946875E}.Release|Win32.Build.0 = Release|Win32 + {C0826A05-9143-4545-B5DE-811C188CB54E}.Debug|Win32.ActiveCfg = Debug|Win32 + {C0826A05-9143-4545-B5DE-811C188CB54E}.Debug|Win32.Build.0 = Debug|Win32 + {C0826A05-9143-4545-B5DE-811C188CB54E}.Release|Win32.ActiveCfg = Release|Win32 + {C0826A05-9143-4545-B5DE-811C188CB54E}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/include/loki/CheckReturn.h b/include/loki/CheckReturn.h new file mode 100755 index 0000000..b4f7131 --- /dev/null +++ b/include/loki/CheckReturn.h @@ -0,0 +1,96 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2007 by Rich Sposato +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author makes no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// + +#ifndef LOKI_CHECK_RETURN_INC_ +#define LOKI_CHECK_RETURN_INC_ + +// $Id$ + + +#include + +namespace Loki +{ + +// ---------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// \class CheckReturn +/// +/// \par Purpose +/// C++ provides no mechanism within the language itself to force code to +/// check the return value from a function call. This simple class provides +/// a mechanism by which programmers can force calling functions to check the +/// return value. Or at least make them consciously choose to disregard the +/// return value. If the calling function fails to use or store the return +/// value, the destructor asserts. +/// +/// \par Return Type +/// The returned value is copied into CheckReturn rather than accessed via a +/// a reference or pointer since return value could be local to a function. +/// CheckReturn works best when the return type is a built-in primitive (bool, +/// int, etc...) a pointer, or an enum (such as an error condition enum). It +/// can work with other types that have cheap copy operations. +//////////////////////////////////////////////////////////////////////////////// + +template < class Value > +class CheckReturn +{ +public: + + /// Conversion constructor changes Value type to CheckReturn type. + inline CheckReturn( Value value ) : + m_value( value ), m_checked( false ) {} + + /// Copy-constructor allows functions to call another function within the + /// return statement. The other CheckReturn's m_checked flag is set since + /// its duty has been passed to the m_checked flag in this one. + inline CheckReturn( const CheckReturn & that ) : + m_value( that.m_value ), m_checked( false ) + { that.m_checked = true; } + + /// Destructor checks if return value was used. + inline ~CheckReturn( void ) + { + // If this assertion fails, then a function failed to check the + // return value from a function call. + assert( m_checked ); + } + + /// Conversion operator changes CheckReturn back to Value type. + inline operator Value ( void ) + { + m_checked = true; + return m_value; + } + +private: + /// Default constructor not implemented. + CheckReturn( void ); + + /// Copy-assignment operator not implemented. + CheckReturn & operator = ( const CheckReturn & that ); + + /// Copy of returned value. + Value m_value; + + /// Flag for whether calling function checked return value yet. + mutable bool m_checked; +}; + +// ---------------------------------------------------------------------------- + +} // namespace Loki + +#endif // end file guardian + +// $Log$ diff --git a/test/CachedFactory/CachedFactory.vcproj b/test/CachedFactory/CachedFactory.vcproj index dd9b9e7..f029eae 100644 --- a/test/CachedFactory/CachedFactory.vcproj +++ b/test/CachedFactory/CachedFactory.vcproj @@ -1,9 +1,9 @@ diff --git a/test/CheckReturn/CheckReturn.dev b/test/CheckReturn/CheckReturn.dev new file mode 100755 index 0000000..60c3e0e --- /dev/null +++ b/test/CheckReturn/CheckReturn.dev @@ -0,0 +1,69 @@ +[Project] +FileName=CheckReturn.dev +Name=CheckReturn +UnitCount=2 +Type=1 +Ver=1 +ObjFiles= +Includes=../../include +Libs= +PrivateResource= +ResourceIncludes= +MakeIncludes= +Compiler= +CppCompiler= +Linker= +IsCpp=1 +Icon= +ExeOutput= +ObjectOutput= +OverrideOutput=0 +OverrideOutputName=CheckReturn.exe +HostApplication= +Folders= +CommandLine= +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +CompilerSettings=1000001000000001000000 + +[Unit1] +FileName=main.cpp +CompileCpp=1 +Folder=CheckReturn +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit2] +FileName=..\..\include\loki\CheckReturn.h +CompileCpp=1 +Folder=CheckReturn +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNr=0 + diff --git a/test/CheckReturn/CheckReturn.vcproj b/test/CheckReturn/CheckReturn.vcproj new file mode 100755 index 0000000..53d4b47 --- /dev/null +++ b/test/CheckReturn/CheckReturn.vcproj @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/CheckReturn/main.cpp b/test/CheckReturn/main.cpp new file mode 100755 index 0000000..568ca21 --- /dev/null +++ b/test/CheckReturn/main.cpp @@ -0,0 +1,155 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2007 Rich Sposato +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author makes no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// + +// $Id$ + +#include + +#include +#include + +using namespace std; + + +// ---------------------------------------------------------------------------- + +typedef ::Loki::CheckReturn< bool > BoolReturn; + +typedef ::Loki::CheckReturn< string > StringReturn; + + +// ---------------------------------------------------------------------------- + +bool NoCheckRequired( void ) +{ + return true; +} + +// ---------------------------------------------------------------------------- + +BoolReturn CheckRequired( void ) +{ + return BoolReturn( true ); +} + +// ---------------------------------------------------------------------------- + +BoolReturn CheckRequired( bool value ) +{ + // By passing false into CheckRequired, CheckRequired calls an overloaded + // version of CheckRequired, thus demonstrating that one can use a function + // call within the return statement and not have to create a named + // temporary variable. + if ( !value ) + return CheckRequired(); + + return BoolReturn( value ); +} + +// ---------------------------------------------------------------------------- + +string GetString( void ) +{ + return string( "a" ); +} + +// ---------------------------------------------------------------------------- + +StringReturn MustUseString( const char * s ) +{ + return StringReturn( s ); +} + +// ---------------------------------------------------------------------------- + +void StringEater( const string & s ) +{ + (void)s; +} + +// ---------------------------------------------------------------------------- + +int main( unsigned int argc, const char * argv[] ) +{ + + if ( 2 == argc ) + { + const char * const a = argv[ argc - 1 ]; + + // okay to call without storing or using return value. + GetString(); + cout << "Called GetString without using return value." << endl; + + // Should not assert since caller stores return value. + const string s = MustUseString( a ); + cout << "Called MustUseString and stored return value." << endl; + + { + // Should not assert since caller passes return value into another + // function, thus converting CheckReturn back into actual type. + StringEater( MustUseString( a ) ); + cout << + "Called MustUseString and passed return value into another function." + << endl; + } + + // This should assert since caller does not check return value. + MustUseString( s.c_str() ); + cout << "Should assert before this line! How did we get here?" << endl; + } + + + // okay to call without storing or using return value. + NoCheckRequired(); + cout << "Called NoCheckRequired without using return value." << endl; + + // Should not assert since caller stores return value. + bool okay = CheckRequired(); + cout << "Called CheckRequired and stored return value." << endl; + + if ( CheckRequired( okay ) ) + { + cout << "Called CheckRequired and used return value." << endl; + } + + { + // Should not assert since caller stores return value ... + BoolReturn checkBool = CheckRequired(); + // and then deliberately ignores it before destructor runs. + (bool)checkBool; + cout << "Called CheckRequired, stored return value, and ignored it." + << endl; + } + + { + // This should not assert since caller deliberately chooses to not + // check return value by casting to return value to correct type. + (bool)CheckRequired(); + } + + { + // This should not assert since caller deliberately chooses to not + // check return value by casting to return value to correct type. + (bool)CheckRequired( false ); + cout << "Made a nested call to CheckRequired." << endl; + } + + // This should assert since caller does not check return value. + CheckRequired(); + cout << "Should assert before this line! How did we get here?" << endl; + + return 0; +} + +// ---------------------------------------------------------------------------- + +// $Log$ diff --git a/test/Function/Function.vcproj b/test/Function/Function.vcproj index fa9381a..8ac13ff 100644 --- a/test/Function/Function.vcproj +++ b/test/Function/Function.vcproj @@ -1,9 +1,9 @@ diff --git a/test/SmallObj/SmallObjBench.cpp b/test/SmallObj/SmallObjBench.cpp index 62b59d0..a06fcf8 100644 --- a/test/SmallObj/SmallObjBench.cpp +++ b/test/SmallObj/SmallObjBench.cpp @@ -274,8 +274,6 @@ template< void testSize() { -//#define LOKI_ALLOCATOR_PARAMETERS ::Loki::SingleThreaded, 4096, 128, 4, Loki::NoDestroy - typedef Base A; typedef Base > B;