2014-11-30 3 views
2

안녕하세요 저는 연산자 오버로딩을 배우고있었습니다. 소멸자를 호출 할 때 프로그램이 중단 된 것으로 나타났습니다. 도움이 필요합니다. 감사소멸자를 호출 할 때 오류가 발생했습니다.

#include<iostream> 
using namespace std; 

class Overload 
{ 
private: 
    int a, *b; 
public: 
    Overload():a(0) {cout << "default\n"; }; 
    Overload(int x); 
    Overload operator+(Overload & rhs); 
    int geta(); 
    int* getb(); 
    void setb(); 
    void PrintVals(const Overload & val); 
    ~Overload(); 
}; 


Overload::Overload(int x) 
{ 
    cout << "Parameterized constructor\n"; 
    a = x; 
    b = new int[a]; 
} 


int Overload::geta() 
{ 
    return a; 
} 


int* Overload::getb() 
{ 
    return b; 
} 

void Overload::setb() 
{ 
    int val; 
    cout << "setting b values\n"; 
    for (int i = 0 ; i <= a; i++) 
    { 
     cin >> val; 

     b[i] = val; 
    } 
} 



Overload Overload::operator+(Overload & rhs) 
{ 
    Overload temp; 
    temp.a = this->a + rhs.a; 
    temp.b = new int[temp.a]; 
    *temp.b = *(this->b) + *(rhs.b); 

    cout << "inside overload + vale of LHS:" << *(this->b) << endl; 
    cout << "inside overload + vale of RHS:" << *(rhs.b) << endl; 
    cout << "inside overload + vale of temp:" << *temp.b << endl; 
    cout << "Address of b(temp):" << temp.b << endl; 


    temp.b++; 
    this->b++; 
    rhs.b++; 

    *temp.b = *(this->b) + *(rhs.b); 

    cout << "inside overload + vale of LHS:" << *(this->b) << endl; 
    cout << "inside overload + vale of RHS:" << *(rhs.b) << endl; 
    cout << "inside overload + vale of temp:" << *temp.b << endl; 

    cout << "Address of b(temp):" << temp.b << endl; 



    return temp; 
} 


Overload::~Overload() 
{ 
cout << "Destructor \n"; 
cout << "Address deallocated b:" << b; 
delete [] b; 
} 



void Overload::PrintVals(const Overload & val) 
{ 
    int val1, *val2; 

    val1 = this->a; 
    val2 = this->b; 

    cout << "Printing values: a: " << val1 << " b:" << *val2; 
} 


int main() 
{ 
    Overload X(1),Y(1),Z; 
    int val1, *val, val2, val3; 
    //Z = X + Y; 

    val1 = Y.geta(); 
    val2 = X.geta(); 

    Y.setb(); 


    val = Y.getb(); 
    printf("val of y b: %d\n",*val); 
    printf("val of x a: %d\n",val1); 

    X.setb(); 

    val = X.getb(); 
    printf("val of x b: %d\n",*val); 
    printf("val of x a: %d\n",val2); 


    Z = X + Y; 

    val = Z.getb(); 
    val3 = Z.geta(); 
    val--; 

    for(int i = 0; i < val3; i++) 
    { 
     printf("address of (b) Z: %p \n",val); 
     printf("val of z b: %d\n",*val); 
     printf("val of z a: %d\n",val3); 
     val++; 

    } 

} 

출력 : ... 소멸자 1 부 (4815,0x7fff73def300)의 malloc : * 객체 0x100200004에 대한 오류 : 포인터가 * 디버깅 malloc_error_break에 중단 점을 설정 할당되지 않은 해제되지 주소 할당 취소 된 b : 0x100200004 (lldb)

답변

2

기본 생성자는 b을 초기화하지 않습니다. 즉, 코드는 유효한 상태의 객체를 생성하지 않습니다. b은 소멸자가 delete[] b을 호출 할 때 오류 일 수 있습니다. 그 밖의 무엇을 기대 했습니까?

관련된 문제는 기본 생성 된 복사본 생성자 및 복사 할당 연산자가 b을 단순히 복사한다는 것입니다. 따라서 복사 된 객체가 파괴되면, 복사 된 객체는 매달려있는 포인터로 남게되어 파괴시 오류가 발생합니다.

기본 강의는 다음과 같습니다. 무엇을하고 있는지 알지 못하는 경우 원시 포인터을 사용하지 마십시오. 오히려 std::vector 또는 std::unique_ptr 또는 그러한 것들을 처리 할 표준에서 제공하는 다른 방법을 사용하십시오.

3

하여 오류의 원인이 두 불쾌한 오류가 있습니다

첫 번째 치명적인 오류가 setb()에서 버퍼 오버 플로우입니다 :

1.Buffer 오버 플로우를 b 점 때문에, a 요소의 배열 원시 포인터의

for (int i = 0; i < a; i++) // strictly < a, not <=a !! 

2.Default 사본을 : 당신은 [A] 메모리가 손상에 위험없이 b를 설정할 수 없습니다 s :

두 번째 치명적인 오류는 구현시 operator+()입니다. 문제는 temp의 복사본 (호출 식의 익명의 임시 객체의 복사본 건설)이 반환됩니다 다음 Z (할당 연산자)에 할당되어 있습니다 :

Overload temp; // you create a logcal temporary object 
... 
temp.b = new int[temp.a]; // you allocate the array 
... 
return b; // you return a COPY of the temp object 
}   // here the local temp object gets destroyed 

하지만 당신은 정의되지하지도 않았다으로 복사 생성자 또는 할당 연산자가 없으면 기본값이 사용됩니다. 이것들은 객체의 구성원 별 복사본을 만듭니다. 즉, 포인터는 그대로 복사됩니다. 결과적으로 Z.b에는 포인터 temp.b 사본이 포함되지만 연산자 +()의 끝에는 temp.b이 이미 삭제되었습니다! 따라서 Z는 매달려있는 포인터를 참조 할 것이고, 특히 main()을 떠날 때 Z의 소멸자가 두 번째로 삭제하려고 시도 할 것이다!

b 포인터를 올바르게 할당하는 복사 생성자와 할당 연산자를 만듭니다. 이것은 두 번째 문제를 해결할 것입니다.

(this->b++처럼 피연산자의 포인터를 증가시키지 마십시오. 피연산자가 바뀌면 피연산자가 바뀌고 delete는 피연산자가 범위를 벗어날 때이를 인식하지 못합니다. 그런데

, 여기에 문제는 없습니다 직접적인 원인은, 두 피연산자의 크기를 추가하여 temp 크기 a을 initalize 경우에도,하지만 당신은 첫 번째 피연산자의 크기 b을 할당합니다.

3. 기타 비고 :

기본 생성자는 명시 적으로 nullptr-b를 초기화하지 않습니다. 그렇게하는 것이 안전한 방법이지만, 여기에있는 문제의 직접적인 원인은 아닙니다.

연산자 +()에서 내부에 액세스하지 않고 온도를 초기화하는 것이 좋습니다. Overload temp (a);은보다 관리하기 쉬우 며 오류가 발생하지 않습니다.

의도가 있는지 알 수는 없지만 b가 가리키는 배열의 첫 번째 값만 추가됩니다. *temp.b = *(this->b) + *(rhs.b);main() 에서처럼 최대 크기 1을 사용하면 여기에 문제가 없습니다. 그러나 미래에는 모든 요소를 ​​복사하는 루프를 사용하는 것이 좋습니다.

마지막 발언 : 클래스 사용자가 이상한 일을 할 수 있다고 생각 해본 적이 있습니까? Overload E, G(0), H(1); E = H+G; 그러면 연산자가 + null 포인터에 액세스하려고하지 않습니까?

관련 문제