2014-12-09 3 views
0

Foo 클래스에 대한 포인터로 Foo1 개체를 반환 한 후 액세스 위반 오류가 발생했습니다. 기능 Foo2::something(int)의 결과는 Foo1 객체입니다. 문제는 Foo** arrayFoo2::something(int)인데 액세스 할 수 없습니다.액세스 위반 0xFEEEFEEE가 구성 요소에 액세스 할 수 없습니다.

class Foo{ 
    int x; 
public: 
    int getX() { return x; } 
Foo& operator=(const Foo &rhs){ 
    x = rhs.x; 
    return *this; 
} 
}; 
class Foo1{ 
    Foo** array; 
    int size; 
public: 
    Foo1(int size){ 
    array = new Foo*[size] 
    for(int i=0; i < size;i++) 
     array[i] = new Foo[size]; 
    } 
Foo1(const Foo1& foo): array(foo.array), size(foo.size){} 
~Foo1(){ 
    for(int i=0; i < size);i++) 
     delete[] array[i]; 
    delete[] array; 
    } 
Foo getFoo(int x, int y){ 
    return array[x][y]; 
} 
void setFoo(int x,int y,Foo foo){ 
    array[x][y] = foo; 
} 
Foo1& operator=(const Foo1& foo){ 
    array = foo.array; 
    size = foo.size; 
} 
}; 
class Foo2{ 
public: 
    Foo1 something(int size){ 
    Foo1 obj(size); 
    return obj;   
    } 
}; 
int main(){ 
Foo2 foo2; 
Foo1 obj = foo2.something(3); 
obj.getFoo(0,0).getX(); // <- access violation here 
} 
+1

'Foo * '대신'std :: vector '은 어떻게 될까요? – Zeta

+3

Foo1 클래스의 복사 생성자가 배열의 복사본을 만들지 않습니다. 포인터 만 복사합니다. 따라서 Foo1 객체가 복사 된 후에는 원본과 사본이 모두 동일한 Foo 배열을 가리키고 있고 Foo1 객체 중 하나가 삭제되면 Foo 배열을 삭제하고 다른 객체에 매달린 포인터가있는 나머지 객체를 남겨 둡니다. 배열에 액세스하려고하면 충돌이 발생합니다. 이를 피하기 위해 복사 생성자 (및 할당 연산자)는 새로운 배열을 할당하고 이전 배열의 내용을 복사해야합니다. 더 나은 방법은 @ Zeta의 조언을 따르고 동적 할당을 피하는 것입니다. –

+0

BTW, 0xFEEEFEEE는 해제 된 힙 메모리에 액세스하는 것을 의미합니다. http://stackoverflow.com/a/127404/487892 – drescherjm

답변

1
Foo1 something(int size){ 
    Foo1 obj(size); 
    return obj;   
} 

당신은 객체 obj를 작성하여 반환한다.

얕은 복사의
Foo1(const Foo1& foo): array(foo.array), size(foo.size){} 

: 배열의 내용이 복사되지 않습니다, 대신, 임시 객체 모두와 mainFoo1 obj이 멤버 array을해야 할 것은 데이터를 복사 돌봐 여부를 당신의 복사 생성자를 확인할 수 있습니다 동일한 데이터를 가리키고 있습니다. 그러나, 나중에 어떻게됩니까? 그 시점에서

Foo1 obj = foo2.something(3); 
// what happens here  ^^^^^ ? 

somethingobj은 파괴 될 것입니다. 그러므로 소멸자가 호출 될 것입니다. 그리고 그 아주 소멸자는 배열의 내용을 삭제합니다.

딥 복사 (새 메모리 할당 및 배열 복사)하거나 참조 계산을 사용하여 배열을 일찍 삭제하지 않도록하십시오. std::vector< std::vector<Foo> > 또는 배관을 숨기는 비슷한 것을 사용하십시오.

추가 참고 사항 : 컴파일러 경고를 사용합니다. 대부분의 void가 아닌 함수는 return을 사용하지 않습니다.

관련 문제