I've been working with a school project, and one of the tasks is to make sure it doesn't leak at all. So, I ran my program through valgrind, and because I'm not using any dynamic memory allocation, I didn't think I would find anything.
Oops, I did. Valgrind gave me this:
==22107== 16 bytes in 1 blocks are definitely lost in loss record 1 of 4
==22107== at 0x100038915: malloc (vg_replace_malloc.c:236)
==22107== by 0x1000950CF: __cxa_get_globals (in /usr/lib/libstdc++.6.0.9.dylib)
==22107== by 0x100094DCD: __cxa_allocate_exception (in /usr/lib/libstdc++.6.0.9.dylib)
==22107== by 0x100051D42: std::__throw_out_of_range(char const*) (in /usr/lib/libstdc++.6.0.9.dylib)
==22107== by 0x100005463: std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >::_M_range_check(unsigned long) const (in ./connect3)
==22107== by 0x100005482: std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >::at(unsigned long) (in ./connect3)
==22107== by 0x1000016E3: connect3::checkIfPositionIsBaseCase(Position) const (in ./connect3)
==22107== by 0x100007BD8: Game::evaluate(Position) (in ./connect3)
==22107== by 0x100007D72: Game::evaluate(Position) (in ./connect3)
==22107== by 0x1000043B4: main (in ./connect3)
==22107==
==22107== LEAK SUMMARY:
==22107== definitely lost: 16 bytes in 1 blocks
==22107== indirectly lost: 0 bytes in 0 blocks
==22107== possibly lost: 0 bytes in 0 blocks
==22107== still reachable: 8,280 bytes in 3 blocks
==22107== suppressed: 0 bytes in 0 blocks
==22107== Reachable blocks (those to which a pointer was found) are not shown.
==22107== To see them, rerun with: --leak-check=full --show-reachable=yes
Well, I took a look at it is coming from my function "checkIfPositionIsBaseCase(Position)". Looking at this method (which my partner wrote), I was actually surprised to see something which may have caused the leak.
Exceptions. Here is the code for that function. (It's pretty much the same thing through out, read the first try catch and you've read them all).
///
/// checkIfPositionIsBaseCase
///
bool connect3::checkIfPositionIsBaseCase(Position aPosition) const {
vector< vector< int > > thisP = aPosition.getBoard();
for( int w = 0; w < thisP.size(); w++ ) {
for( int h = 0; h < thisP.at(w).size(); h++ ){
int thisS = thisP.at( w ).at( h );
if( thisS != 0 ){
try{
if( thisP.at( w - 1 ).at( h - 1 ) == thisS ){
if( thisP.at( w - 2 ).at( h - 2 ) == thisS ){
return true;
}
}
}catch( out_of_range& ){}
try{
if( thisP.at( w ).at( h - 1 ) == thisS ){
if( thisP.at( w ).at( h - 2 ) == thisS ){
return true;
}
}
}catch( out_of_range& ){}
try{
if( thisP.at( w + 1 ).at( h - 1 ) == thisS ){
if( thisP.at( w + 2 ).at( h - 2 ) == thisS ){
return true;
}
}
}catch( out_of_range& ){}
try{
if( thisP.at( w - 1 ).at( h ) == thisS ){
if( thisP.at( w - 2 ).at( h ) == thisS ){
return true;
}
}
}catch( out_of_range& ){}
try{
if( thisP.at( w + 1 ).at( h ) == thisS ){
if( thisP.at( w + 2 ).at( h ) == thisS ){
return true;
}
}
}catch( out_of_range& ){}
try{
if( thisP.at( w - 1 ).at( h + 1 ) == thisS ){
if( thisP.at( w - 2 ).at( h + 2 ) == thisS ){
return true;
}
}
}catch( out_of_range& ){}
try{
if( thisP.at( w ).at( h + 1 ) == thisS ){
if( thisP.at( w ).at( h + 2 ) == thisS ){
return true;
}
}
}catch( out_of_range& ){}
try{
if( thisP.at( w + 1 ).at( h + 1 ) == thisS ){
if( thisP.at( w + 2 ).at( h + 2 ) == thisS ){
return true;
}
}
}catch( out_of_range& ){}
}
}
}
///
/// One possibility
///
for (int i = 0; i < thisP.size(); i++) {
for (int j = 0; j < thisP.at(i).size(); j++) {
if (thisP.at(i).at(j) == 0) {
return false;
}
}
}
return true;
}
I did a little reading, and it looks like the fact that I am catching exceptions means that I am leaking memory, but I don't know how to resolve this. How can I refactor the code so I don't leak memory?