2010-12-12 3 views
4

나는 아직도 C++을 배우고 있으며 명백한 질문이 있거나 어쩌면 내가 무엇을하려고하는지 모를 수도 있습니다. 나는 행렬 (제대로 작성된 소멸자가있는 클래스)을 가지고 새로운 행렬을 생성하여 새로운 행렬에 대한 참조를 반환하는 함수를 가지고있다. 이 행렬에 수만 번 반복 할 필요가 있으므로 메모리 누수가 없는지 확인해야합니다. 그래서 문제는 다음 행간을 위해 공간을 만들기 위해 더 이상 필요하지 않은 행렬을 어떻게 적절하게 삭제할 수 있는가하는 것입니다. 여기에 내가 누출이없는 얻으려고 코드입니다 :C++ delete reference

DynamicMatrix<double> x0 = getX0(n); 

DynamicMatrix<double>exactU = getExactU(n); 

DynamicMatrix<double> b = getB(n) * w; 

DynamicMatrix<double> x1 = getX1(x0, b, w, n); 

while(!isConverged(exactU,x1,e)){ 
    delete x0; //<<<<< This doesn't work. Nor does delete &x0. 
    x0 = x1; 
    x1 = getX1(x0, b, w, n); 
} 

getX의 각() 메소드 행렬에 대한 포인터를 만들고, 그리고) getX0 (같이 매트릭스에 대한 참조를 반환

DynamicMatrix<double> &getX0(int n){ 
    DynamicMatrix<double>* mat1 = new DynamicMatrix<double>(n * n,1); 
    for (int i = 1 ; i <= n; i++){ 
     for (int j = 1; j <= n; j++){ 
      mat1->set((i-1)*n +j, 1, 0); 
     } 
    } 
    return *mat1; 
} 

그러면 포인터가 필요하기 때문에 'delete X0'오류가 발생합니다. '& X0'은 해제 된 포인터가 할당되지 않았다고 말합니다. 이 작업을 수행하는 올바른 방법은 무엇입니까? 아니면 완전히 잘못된 것을하고 있습니까? 크기가 너무 크고 반복 횟수가 너무 많으므로 내 하드 드라이브에서 공간이 부족하여 메모리 누출이 많다는 것을 의미합니다. getX() 포인터를 반환하는 경우

+0

하드 드라이브의 메모리 누수로 공간이 부족한 경우 페이징 파일이 너무 커지도록 구성되어 있음을 의미합니다. –

답변

6

스트로브 스트 룹 르 '리에 Fhtagn를 호출 할 수 있어야합니다.

쓰기 MyType myVar = MyFunction()은 반환 유형 myFunction을 인수로 허용하는 생성자를 사용하여 새로운 객체를 만듭니다. myFunction에 의해 반환 된 것은 모두 무시됩니다. 예를 들어, getX0은 동적으로 할당 된 개체에 대한 참조를 반환하므로 유출됩니다.

심각하게도, 스택 (new 제외)의 행렬을 만들어서 그대로 반환하십시오.어쨌든 내부에서 데이터를 동적으로 할당하는 것처럼 보이기 때문에 너무 많은 문제가 발생해서는 안되며, NRVO가 복사를 피하기 위해 적용될 것으로 의심됩니다 (반환 된 행렬은 해당 위치에 직접 생성됩니다.) x0x1 마술 실제 데이터를 복사하는 대신 교환 동작 (매우 고속이다) 포인터 스왑 측면에서 동적 매트릭스 상에 구현 될 수 있으므로

x0.swap(x1); 
DynamicMatrix<double> temp = getX1(x0, b, w, n); 
x1.swap(temp); 

이 매우되어야 다음과 같이 하단에 구현 될 수있다 빨리.

+0

+1 Lovecraft. – Kos

+1

매트릭스 클래스에 스왑을 구현하는 것은 좋은 생각입니다. 그러나 마지막 두 줄은'getX1 (x0, b, w, n) .swap (x1);'으로 쓰여질 수 있습니다. 이것은 지역 변수의 내용을 함수의 반환 값으로 바꾸기 위해 흔히 볼 수있는 스타일입니다. –

+0

행렬 클래스는 힙에 데이터를 동적으로 저장합니다. 스왑 함수를 오버라이드해야하나요, 아니면 내 자신을 쓸 필요가없는 설명처럼 작동해야합니까? – jakev

1

, 첫 번째 라인으로 작성해야 : 새 포인터를 반환으로 더 나을

DynamicMatrix<double>* x0 = getX0(n); 

. 그런 다음 아래에 몇 줄을 표시하면서 삭제해야합니다. 당신이 boost::shared_ptr를 사용하여 문제를 많이 절약 할 수 있습니다 그러나

참고 :

typedef boost::shared_ptr<DynamicMatrix<double> > dyn_matrix_ptr; 

dyn_matrix_ptr x0 (getX0(n)); 
// use x0 as a normal pointer 
... 
// You don't have to manually delete it, it will be deleted automatically. 
2

당신은 포인터를 사용해야합니다. 명세서

DynamicMatrix<double> x0 = getX0(n); 

행렬의 복사본을 만듭니다.

DynamicMatrix<double> x0 = getX0(n); 

당신은 반드시 포인터를 사용 필요 없다 : 당신은 그런

DynamicMatrix<double> *x0 = getX0(n); 
... 
delete x0; 
+0

ok,하지만 이제 어떻게하면 x0 = x1이되어 각각이 별도의 복사본을 가리킬 수 있습니까? – jakev

+0

@ JakeVA :'delete x0; x0 = new DynamicMatrix (x1); ' –

+0

@ JakeVA :하지만 복사본을 원하지 않으면 소유권을 넘겨 줘야합니다. –

0

버그가 여기에있다

DynamicMatrix<double> *getX0(int n){ 
    DynamicMatrix<double>* mat1 = new DynamicMatrix<double>(n * n,1); 
    ... 
    return mat1; 
} 

를 원한다. 새 객체에 대한 참조를 반환 할 수 있습니다. 메모리를 지우려면 reference의 주소를 취하십시오. 참조 주소를 지정하면 참조 대상 주소가 제공됩니다. 당신은

// receive newed memory in a reference 
DynamicMatrix<double>& x0 = getX0(n); 

// &x0 should give you the address of the allocated memory. 
delete &x0; 
0

DynamicMatrix<double>에 대한 규칙은 근본적으로는 int과 동일합니다.

'auto'변수로 스택에 할당 된 경우이를 정리하는 올바른 방법은 아무 것도하지 않는 것입니다. 범위를 벗어나게하십시오. 이 경우에 가능한 한 코드를 정렬하려고합니다.

'new'로 할당 된 경우 'delete'로 정리하십시오.

동적으로 할당하지 않은 다음 참조로 반환하십시오. 포인터를 반환합니다. 사실, 그렇게하지 마십시오. 스마트 포인터 클래스를 사용하십시오. 부디.

필요없는 경우 동적으로 할당하지 마십시오. 지역 값을 만들고 반환하십시오.으로 을 반환하십시오. 이것은 비 정적 로컬에 대한 참조를 반환 할 수 없다는 사실을 처리하는 방법입니다. 은 다음과 같이 작성하는 것이 좋습니다.

int& give_me_a_value() { 
    int* result = new int(rand()); 
    return *result; 
} 

는 다시 : DynamicMatrix<double>에 대한 규칙은 근본적으로 그들이 int위한 동일합니다. 이것이 복사 생성자, 대입 연산자 및 소멸자를 구현하는 이유입니다. 이렇게하면 실제로는 예상대로 작동합니다.

+0

당신이 준 예제 .. 나는 여전히 참조와 포인터 사이의 차이점을 찾아 내고 그들 사이를 변환하려고 노력 중이다. 그래서 솔직히 말해서 나는 그런 코드를 작성할 수 있습니다. 그것이 내가 행렬 수업에서 한 일이며, 그것이 옳다고 생각했습니다. 참조를 반환하면 사본이 어떻게 생성되는지는 내게 직관적이지 않습니다. – jakev

+0

음 ...이 코드를 살펴보십시오.'int give_me_a_value() {int result = rand(); 반환 결과;'그게 훨씬 더 잘, 음, ** 정상적인 ** 지옥 보이지 않는가? 나는 정말로 그것을 원합니다, 그렇지 않으면 당신은 매우 ** 매우 ** 이상한 참고 자료로부터 배우고 있습니다.참조를 되 돌리는 것은 ** 사본을 만들지 않습니다 ** 그것이 요점입니다. ** 값으로 ** 돌아 오는 ** 않습니다. –

+0

일반적으로 함수가 참조를 반환하면 ** 함수가 ** 호출되었을 때 이미 있던 ** 참조를 반환해야합니다. –