Утечка в коде исключения C ++ - PullRequest
1 голос
/ 12 ноября 2010

Я работал со школьным проектом, и одна из задач - убедиться, что он вообще не протекает.Итак, я запустил свою программу через valgrind, и, поскольку я не использую динамическое выделение памяти, я не думал, что что-нибудь найду.

Упс, я сделал.Вальгринд дал мне это:

==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

Ну, я посмотрел, что это происходит из моей функции "checkIfPositionIsBaseCase (Position)".Глядя на этот метод (который написал мой партнер), я был удивлен, увидев что-то, что могло вызвать утечку.

Исключения.Вот код для этой функции.(Это почти одно и то же, прочитайте первую попытку catch, и вы прочитали их все).

///
/// 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;
}

Я немного прочитал, и похоже, что я ловлю исключенияозначает, что у меня утечка памяти, но я не знаю, как решить эту проблему.Как я могу изменить код, чтобы не допустить утечки памяти?

Ответы [ 2 ]

2 голосов
/ 12 ноября 2010

Исключения лучше использовать для исключительных случаев, хотя здесь они будут встречаться довольно часто (по крайней мере, 4 раза за внешний цикл ...)

Это может быть легко рефакторинг:

typedef std::vector< std::vector<int> > board_type;

namespace {
  bool check(board_type const& board, int val, int w1, int h1, int w2, int h2)
  {
    if (w1 < 0 || w2 < 0) { return false; }
    if (w1 >= board.size() || w2 >= board.size()) { return false; }
    if (h1 < 0 || h2 < 0) { return false; }
    if (h1 >= board[w1].size() || h2 >= board[w2].size()) { return false; }
    return board[w1][h1] == val && board[w2][h2] == val;
  }
} // anonymous namespace

bool connect3::checkIfPositionIsBaseCase(Position aPosition) const {

  vector< vector< int > > thisP = aPosition.getBoard();

  bool encounteredZero = false;

  for( int w = 0; w < thisP.size(); w++ ) {
    for( int h = 0; h < thisP.at(w).size(); h++ ){
      int val = thisP[w][h];
      if (val == 0) { encounteredZero = true; continue; }

      // Check in all directions with a clock-wise rotation
      if (check(thisP, val, w-1, h-1, w-2, h-2)) { return true; }
      if (check(thisP, val, w  , h-1, w  , h-2)) { return true; }
      if (check(thisP, val, w+1, h-1, w+2, h-2)) { return true; }
      if (check(thisP, val, w+1, h  , w+2, h  )) { return true; }
      if (check(thisP, val, w+1, h+1, w+2, h+2)) { return true; }
      if (check(thisP, val, w  , h+1, w  , h+2)) { return true; }
      if (check(thisP, val, w-1, h+1, w-2, h+2)) { return true; }
      if (check(thisP, val, w-1, h  , w-2, h  )) { return true; }
    }
  }

  return !encounteredZero;
}

И там не будет никаких исключений :) Мне также легче проверить, что проверки правильные и исчерпывающие ...

2 голосов
/ 12 ноября 2010

Важно понимать разницу между утечкой памяти на повторяющейся основе (которая может привести к исчерпанию) и наличием некоторого базового кода поддержки или библиотеки, имеющего однократный шаг инициализации, который получает некоторую кучную память, которую он будет использовать, пока программа запускается (в этом случае на самом деле бесполезно или необязательно освобождать / удалять память при завершении программы, и это может быть довольно хлопотно при попытке ее организовать).

Здесь __cxa_get_globals, кажется, выполняет однократный malloc.

Короткая история: просто убедитесь, что вы не получите несколько неизданных блоков (или больше), когда эти исключения вызываются неоднократно ....

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...