2010-01-03 10 views
1

FeatureCount와 FeatureCount의 배열을 가리키는 포인터 멤버가 _rects 인 클래스 FeatureRandomCounts에 대한 대입 연산자에 과부하가 걸렸습니다. 다른 날짜 멤버는 비 포인터 :오버로딩 연산자에서 세그먼트 화 오류 =

FeatureRandomCounts & FeatureRandomCounts::operator=(const FeatureRandomCounts &rhs) 
{ 
    if (_rects) delete [] _rects; 

    *this = rhs; // segment fault 

    _rects = new FeatureCount [rhs._dim]; 
    for (int i = 0; i < rhs._dim; i++) 
    { 
    _rects[i]=rhs._rects[i]; 
    } 

    return *this;  
} 

누군가 실마리가 있습니까? 고마워, 안부!

답변

5

언급 한대로 무한 재귀가 있습니다. 그러나,에 추가, 여기 = 연산을 구현하는 절대 안전한 방법 :

struct T { 
    T(T const& other); 
    T& operator=(T copy) { 
    swap(*this, copy); 
    return *this; 
    } 
    friend void swap(T& a, T& b); 
}; 

는 정확한 복사 ctor에 스왑 및 예외 안전성과 모든 가장자리 경우가 당신을 위해 처리됩니다 쓰기!

복사본 매개 변수는 값이으로 전달 된 다음 변경되었습니다. 현재 인스턴스가 파기해야하는 리소스는 복사본이 파괴 될 때 처리됩니다. 이것은 current recommendations을 따르고 self-assignment을 깨끗하게 처리합니다.그것은 수동으로 관리 회원 (페이지) 또는 RAII/SBRM 스타일의 구성원 () 중 하나와 함께 작동


#include <algorithm> 
#include <iostream> 

struct ConcreteExample { 
    int* p; 
    std::string s; 

    ConcreteExample(int n, char const* s) : p(new int(n)), s(s) {} 
    ConcreteExample(ConcreteExample const& other) 
    : p(new int(*other.p)), s(other.s) {} 
    ~ConcreteExample() { delete p; } 

    ConcreteExample& operator=(ConcreteExample copy) { 
    swap(*this, copy); 
    return *this; 
    } 

    friend void swap(ConcreteExample& a, ConcreteExample& b) { 
    using std::swap; 
    //using boost::swap; // if available 
    swap(a.p, b.p); // uses ADL (when p has a different type), the whole reason 
    swap(a.s, b.s); // this 'method' is not really a member (so it can be used 
        // the same way) 
    } 
}; 

int main() { 
    ConcreteExample a (3, "a"), b (5, "b"); 
    std::cout << a.s << *a.p << ' ' << b.s << *b.p << '\n'; 
    a = b; 
    std::cout << a.s << *a.p << ' ' << b.s << *b.p << '\n'; 
    return 0; 
} 

알 수 있습니다.

+0

아직 알 수 없습니다. 구조체가 템플릿입니까? 그래서 스왑으로 복사가 원래 것입니다 * this? – Tim

+0

감사합니다. 스왑도 "복사"를 변경합니까? 이게 과제 이상인가요? – Tim

14
*this = rhs; 

은 작성중인 함수 인 operator =()를 호출합니다. 무한 반복 재귀, 스택 오버플로, 충돌.

또한 C 스타일 배열 대신 std :: vector를 사용하면 operator =()를 전혀 구현할 필요가 없을 것입니다.

+0

감사합니다. 닐! 내 코드에서 C 배열은 std :: vector보다 선호된다. 그러나 그것은 여전히 ​​가능한 해결책입니다. – Tim

+5

벡터 배열보다 C 배열을 선호한다면, 틀렸고 엄청난 양의 불필요한 작업을 스스로 해결할 수 있습니다. –

+2

할당 연산자를 올바르게 쓸 수 없다는 사실은 동적으로 할당 된 배열을 사용하는 것과 관련된 함정을 모를 수 있음을 의미합니다. 즉, 반드시 std :: vector <>를 사용해야합니다. C 배열을 선호하는 것은 이유가 아니라 실제로 일어나는 일에 대한 이해 부족입니다. –

3

다음 줄 :

*this = rhs; // segment fault 

재귀 스택 오버 플로우의 결과로 당신의 operator=() 함수를 호출합니다.

다양한 멤버 필드의 직선적 인 할당으로 대체해야합니다.

As Neil said과 같은 코드를 사용하면 std::vector<>과 같은 코드를 사용하면 많은 책임을 코드에서 제거 할 수 있습니다. 어떤 이유로 든 std::vector<>을 사용할 수 없거나 사용하지 않으려는 경우 할당 연산자에 '스왑 이디엄'을 사용하는 것이 좋습니다. 이렇게하면 함수의 예외가 안전 해집니다 (배열 FeatureCount에 대한 메모리 할당이 실패하고 예외가 발생하면 원래 할당 된 객체는 변경되지 않습니다). 다음과 같은 뭔가 :

void FeatureRandomCounts::swap(FeatureRandomCounts& other) 
{ 
    FeatureCount* tmp_rects = other._rects; 
    int tmp_dim    = other._dim; // or whatever type _dim is 

    // similarly for other members of FeatureRandomCounts... 

    // now copy the other contents to 
    this->_rects = other._rects; 
    this->_dim = other._dim; 

    // assign other members of rhs to lhs 

    other._rects = tmp_rects; 
    other._dim = tmp_dim; 

    // etc. 

    return; 
} 

지금 과제가 같이 할 수 있습니다 당신은이 작업을 할 수있는 적절한 복사 생성자가 필요

FeatureRandomCounts & FeatureRandomCounts::operator=(const FeatureRandomCounts &rhs) 
{ 
    FeatureRandomCounts tmp(rhs); // make a copy 

    tmp.swap(*this);    // swap the contents of the copy and *this 

    return *this; 
            // the contents of tmp (which has the old 
            // stuff that was in *this) gets destructed 
} 

참고하지만, 주어진 Big 3 rule 이미 적절한 복사 ctor에 필요 .

+1

swap()을 구현할 때 적어도 실제 std :: swap()을 사용하여 실제 멤버를 교체 할 수 있습니다. –

+0

@Martin - 당신 말이 맞아요. OP가'std :: vector '를 사용할 수 없거나 사용할 수 없다는 것을 지적했기 때문에 나는'std :: anything'을 명확하게 처리했습니다. 나는 그것을 분명히해야하고 나중에'std :: swap'이 사용되어야 함을 나타 내기 위해 대답을 업데이트 할 것이다. (사실, 적절한'using' 선언을 가진 비 - 범위 'swap()이어야한다. 그래서 가장 적절한 'swap()'이 선택되고,'std :: swap'이 최후의 리조트와 일치합니다.) –

4
*this = rhs; // segment fault 

이 할 수있는 방법은 결정적으로 하지입니다. 내장 된 대입 연산자를 호출하지 않고 =을 재귀 적으로 호출합니다. 변수를 하나씩 할당하십시오. 게으르지 마라.

+0

감사합니다. 나는 게으르다. 그렇다면 기본 할당 연산자를 호출 할 수 있습니까? – Tim

+0

아니요, 일단 자신의 것을 선언하면 컴파일러는 생성하지 않습니다 (동일한 서명을 가질 수는 없습니다). –

관련 문제