2009-04-27 2 views
1

의 내가 두 정점을 추가하는 방법으로 정점이라는 구조를 가지고 있다고 가정 해 봅시다 : 나는 두 개의 정점을 추가하고 vector<vertex*>에 결과를 추가 할 또 다른 호출 함수에서힙의 벡터에 객체 값을 추가하는 것이 언제 안전합니까?

struct vertex { 
    float x, y, z; 

    // constructs the vertex with initial values 
    vertex(float ix, float iy, float iz); 

    // returns the value c = this + b 
    vertex operator+(vertex b); 
}; 

vertex::vertex(float ix, float iy, float iz){ 
    this->x = ix; this->y = iy; this->z = iz; 
} 

vertex vertex::operator+(vertex b){ 
    vertex c; 
    c.x = this->x + b.x; 
    c.y = this->y + b.y; 
    c.z = this->z + b.z; 
    return c; 
} 

합니다. 반환 된 값을 사용하여 주어진 벡터에 추가하는 것이 안전한 경우는 언제입니까? 만약 그렇다면 어떻게 구현할 수 있습니까? 현재 함수가 종료되면 회수한다 자동 또는 임시 변수에 대한 포인터를 저장되기 때문에, 예를 들어

,

vector<vertex*> v; 
vertex a(1, 2, 3); 
vertex b(4, 5, 6); 
v.push_back(&(a + b)); 

답변

2

이것은 안전하지 않다.

자동 할당 된 개체와 동적으로 할당 된 개체를 혼용하면 심각한 위험이 있습니다. 경우에 따라 자동 할당을 완전히 허용하지 않는 것이 가장 좋습니다 (예 : 생성자를 비공개로 설정하고 팩토리 메소드를 사용하여 새 인스턴스를 생성). 그런 다음 어느 시점에서이를 제거해야 할 책임이 있습니다.

두 번째 옵션 (원하는 것은 아님)은 모든 것을 값으로 수행하는 것입니다. 꼭지점이 아닌 꼭지점이있는 벡터를 사용하고, 꼭지점을 저장할 때 복사하면됩니다. 클래스가 작성된 방식, 모든 필드는 프리미티브이므로이 방법이 충분히 좋을 수 있으며 성능 또는 심층 복사 의미 문제에 부딪치지 않을 수 있습니다.

+0

비트를 명확히하지만, 연산자 함수에서 포인터를 반환하지 않고이 작업을 수행하는 안전한 방법은 무엇입니까? 서로 다른 사업자를 함께 연결할 수 있기를 원합니다. 즉 a + b + c. – Asuah

+0

pass-by-value 및 return-by-value 의미를 사용하는 경우에도이 작업을 계속 수행 할 수 있습니다. 그것은 안전 할 것이다. 꼭지점에 대한 포인터 벡터 벡터가 아닌 꼭지점 개체 벡터 만 수행하면됩니다. – Uri

+0

스마트 포인터를 사용하는 것이 여기 또 다른 옵션입니다. –

1

임시 객체에 대한 포인터를 벡터에 추가하므로 절대로 저장되지 않습니다. 이 임시 객체는 라인이 실행 된 후 파괴되어 벡터에 유효하지 않은 포인터가 남습니다.

두 가지 가능성이 있습니다. 어느 쪽이든 당신은 벡터의 포인터를 저장하고 대신 vector<vertex>를 사용하거나 당신이 그것을 추가 할 때 명시 적으로 임시 객체의 새 복사본을 할당하지 않습니다

v.push_back(new vertex(a+b)); 
1

또 다른 대안은 표준 컨테이너에 스마트 포인터를 삽입하고, boost : shared_ptr와 같이 공유 포인터가 메모리 관리를 담당 할 것이기 때문이다. 그러나 Shared_Ptr vertex :: operator + (정점 b)에서 공유 포인터를 반환해야합니다. 즉, 반환 값이 여전히 힙에 있음을 의미합니다.

부스트 : shared_ptr에 익숙하지 않은 경우 다른 게시물에서 제안한대로 가치에 따라 모든 것을 수행하십시오. 이것은 실제로 stl 표준 연습입니다.

1

벡터에 추가 할 정점 값이 이 아니고 힙의이 아니므로 안전하지 않습니다. 반환 된 정점 객체는 스택에 있으므로 현재 함수가 종료되면 메모리 위치가 덮어 쓸 수 있습니다. 현재 함수가 끝난 후에 벡터 (또는 그것의 복사본)가 지속되면 포인터가 여전히 유효한 정점 객체를 참조한다는 보장이 없습니다.

이 상황에서 가장 위험한 부분은 해당 정점 개체가 만들어진 함수가 끝난 후 오랫동안 메모리에서 살아남을 수 있다는 것입니다. 나는 이것을 한 번 보았는데, 한 학생이 매우 긴 생성자에서 값 객체에 대한 포인터를 벡터에 채 웠습니다. 벡터는 객체의 멤버 필드이므로 생성자가 끝난 후에도 여전히 존재합니다. 생성자가 너무 길기 때문에 벡터가 가리키는 값 객체는 다른 함수의 중간까지 덮어 쓰지 않았습니다. 디버거에서 벡터의 내용을 관찰하면 객체가 메모리에서 자발적으로 손상된다는 착각의 환상을 만들었습니다.

이러한 꼭지점을 포인터로 꼭 저장해야하는 경우가 아니면 vector<vertex*> 대신 vector<vertex> 값 개체로 벡터를 저장하는 것이 가장 안전한 전략입니다. 당신은 여전히 ​​다른 사업자들을 함께 묶을 수있을 것입니다; 실제로 포인터를 역 참조 할 필요가 없으므로 값 개체로 함께 쉽게 변경해야합니다.

관련 문제