2014-10-20 1 views
0
#include <iostream> 
#include <fstream> 
#include <initializer_list> 
#include <memory> 

class OutOfMem { }; 
class IndexOutOfRange { }; 
class NoFile { }; 
class InvalidFileFormat { }; 
class WrongDim { }; 

class Array { 
public: 
    Array(double * arr, const unsigned c) : array(arr), columns(c) { } 
    double &operator [] (const unsigned i) 
    { 
     if(i >= columns) 
      throw IndexOutOfRange(); 
     return array[i]; 
    } 
private: 
    double * array = nullptr; 
    unsigned columns; 
}; 

class 2DArray { 

public: 
    2DArray(std::fstream &is) 
    { 
     if(!is) 
      throw NoFile(); 
     if(!(is >> rows >> columns)) 
      throw InvalidFileFormat(); 
     matrix = new (std::nothrow) double *[rows]; 
     if(!matrix) 
      throw OutOfMem(); 
     use = new (std::nothrow) std::size_t(1); 
     if(!use) 
      throw OutOfMem(); 
     for(unsigned i = 0; i < rows; i++) 
     { 
      matrix[i] = new(std::nothrow) double[columns]; 
      if(!matrix[i]) 
       throw OutOfMem(); 
     } 
     for(unsigned i = 0; i < rows; i++) 
      for(unsigned j = 0; j < columns; j++) 
      { 
       double temp; 
       if(!(is >> temp)) 
        throw WrongDim(); 
       matrix[i][j] = temp; 
      } 

    } 
    ~2DArray() 
    { 
     if(--*use == 0) 
     { 
      for(unsigned i = 0; i < rows; i++) 
       delete [] matrix[i]; 
      delete [] matrix; 
      delete use; 
     } 
    } 
    Array operator [] (const unsigned i) 
    { 
     if(i >= rows) 
      throw IndexOutOfRange(); 
     if(*use == 1) 
      return Array(matrix[i], columns); 
     else 
     { 
      double ** copy; 
      copy = new (std::nothrow) double *[rows]; 
      for(unsigned i = 0 ; i < rows; i++) 
      { 
       copy[i] = new (std::nothrow) double[columns](); 
       if(!copy[i]) 
        throw OutOfMem(); 
       for(unsigned j = 0 ; j < columns; j++) 
        copy[i][j] = matrix[i][j]; 
      } 
      --*use; 
      matrix = copy; 
      use = new std::size_t(1); 
      return Array(matrix[i], columns); 
     } 
    } 
private: 
    unsigned rows; 
    unsigned columns; 
    double ** matrix = nullptr; 
    std::size_t * use; 
}; 

파일에서 행렬을 읽는 데 사용되는 프로그램에서 문제가 발생하지만 잘못된 값을 추가하여 파일을 다시 포맷 할 때 메모리 누수가 발생합니다. 소멸자를 호출해야하지만 던져진 후에도 오브젝트가 남아있는 경우가 거의 없습니다. 모든 팁 ?? 메모리 검사를 위해 valgrind를 사용하고 있습니다.예외를 throw 한 후 메모리 누수

+6

['std :: vector'] (http://en.cppreference.com/w/cpp/container/vector)는 친구입니다. 'new'와'delete'는 적입니다. –

+0

@CaptainObvlious 알아. 보통 나는 거의 새로운 것을 사용하지 않고 삭제합니다. 하지만 그건 임무를위한 것이었고 나는 컨테이너를 사용하지 말라는 의무가있었습니다. – user3119781

+0

생성자는'istream'을 사용하여 입력 스트림을 가져올 수 있습니다. –

답변

3

이 라인이 실패 할 경우 2DArray(std::fstream &is)에 무슨 상상 :

use = new (std::nothrow) std::size_t(1); 

당신은 OutOfMem 예외를 던져,하지만 당신은 몇 줄 위의 matrix에 의해 할당 된 메모리를 삭제하지 마십시오. 그리고 당신은 당신의 코드에 그러한 많은 사례들을 가지고 있습니다.

당신은 두 가지 옵션이 있습니다

  1. 조심스럽게, 생성자에서, 캐치 예외를 할당되고 있는지 확인 필요한 것을 삭제하고 예외를 다시 던진다. 이 경우 유용한 전략은 모든 것을 0으로 초기화하고 예외 처리기에서 모든 포인터에 대해 delete을 호출하기 만하면됩니다.
  2. (훨씬 더 좋습니다.) std::vector과 같은 표준 컨테이너 또는 적어도 수동으로 메모리를 정리할 필요가없는 std::unique_ptr과 같은 스마트 포인터를 사용하십시오.

업데이트 : 나에게 분명해 보인 것을 잊어 버렸습니다. 예외가 생성자에서 발생하면 개체가 생성되지 않아서 소멸자가 호출되지 않습니다. 그리고 부름을 받았을지라도 귀하의 경우에 초래할 재앙적인 결과에 대해 생각해보십시오.

+0

그는 소멸자에게 메모리 할당을 남겨두고 있습니다. 소멸자는 객체가 성공적으로 생성되지 않았기 때문에 호출되지 않습니다. – Nard

3

소멸자가 호출되지 않는 이유는 생성자에서 예외가 발생하면 해당 개체가 이 아닌 것으로 간주되어으로 간주되기 때문입니다.

읽어 주셔서 감사합니다.