2009-11-09 4 views
3

저는 C++에별로 좋지 않지만 평판 기반 시스템을 테스트해야합니다. 우분투 시스템에서 실행할 때 segfault를주는 코드 조각이 아래에 나와 있습니다. 주석에서 두 함수 "tackleFirstHandInfo()"와 "updateReputation()"을 개별적으로 올바르게 실행했지만 다른 함수에서 하나의 함수를 호출하면 충돌이 발생합니다. 어떤 도움이라도 미리 감사드립니다. 코드는 다음과 같습니다 :stl 맵의 세그먼트 오류 <>

교장 문제의
"ex.h" 

#ifndef _ex_h 
#define _ex_h 
#include "iostream" 
#include <map> 
#define FADING 0.9 
enum Behaviour {FORWARDING, NOTFORWARDING}; 

class Rating 
{ 

private: 
    double reputation; 

public: 

    Rating() { reputation = 5.0; } 
    Rating(double rep) {reputation = rep;} 

    ~Rating() {} 

    double getRep() { return reputation; } 

    void updateRep(Behaviour behaviour) { 
     if (behaviour == FORWARDING) 
      reputation = reputation + 1;  
     else 
      reputation = reputation - 1;  
    } 

}; 

#endif 

"ex.cc" 

#include <map>         
#include <string> 
#include <iostream> 
#include "ex.h"       
using namespace std; 
typedef map<int, Rating*> ratingTable; 
class RepSys { 
private: 
    ratingTable repTable; 
    map<int, Rating*> fHandInfo; 
    Rating* rating; 

public: 
    RepSys(){} 
    ~RepSys(){} 

    void tackleFirstHandInfo(int address, Behaviour behaviour) 
    /* This Function and the function below individually run correctly */ 
    { 
     map<int, Rating*>::iterator it; 
     it=fHandInfo.find(address); 
     if (it == fHandInfo.end()) { 
      cout << "Adding New Entry for (fHandInfo) "<< address <<endl; 
      rating = new Rating(); 
      fHandInfo[address] = rating; 
     } 
     (it->second)->updateRep(behaviour); 
     cout<<"First Hand Reputation of "<<address<<"\t is ="<< (it->second)->getRep()<<endl; 
     updateReputation(address, behaviour); // This causes SegFault !!!! 
     return; 
    } 

    void updateReputation(int address, Behaviour behaviour) 
    { 
     map<int, Rating*>::iterator it; 
     it = repTable.find(address); 
     if (it == repTable.end()) { 
      cout << "Adding New Entry for (repTable) "<< address <<endl; 
      rating = new Rating(); 
      repTable[address] = rating; 
     } 
     (it->second)->updateRep(behaviour); 
     cout<<"Reputation of "<<address<<"\t is ="<< (it->second)->getRep()<<endl; 
    } 
}; 

int main() { 
    int address;  
    RepSys repsys; 
    while (address != 0) 
    {         
     cout << "Address\n"; 
     cin >> address; 
     repsys.tackleFirstHandInfo(address, FORWARDING); 
    } 
    return 0; 
} 
+0

누군가 서식을 수정할 수 있습니까? –

+0

서식을 잘 관리하십시오! – jldupont

+0

이제 읽을 수 있습니다. 비록 사람들이 어쨌든 그것을 알아 냈습니다. –

답변

10

하나는 두 기능에서 발생하고 이것이다 : 마지막 포인트는 다음이 dereferencable 아니므로 it->second가있다 않습니다

if (it == fHandInfo.end()){ 
    // Some code that doesn't alter 'it' 
} 
(it->second)->updateRep(behaviour); 

it 경우 정의되지 않은 동작. 무언가를 삽입하고 it이 가리 키도록하려면 find을 다시 실행하거나 반복기 (또는 반복자를 포함하는 쌍)를 반환하는 삽입 메소드를 사용하고 it을 반환 값의 올바른 부분에 다시 할당하십시오 .

편집

몇 더 많은 포인트 :

class RepSys { 
private: 
    ratingTable repTable; 
    map<int, Rating*> fHandInfo; 
    Rating* rating; 

이미 typedef 에드 ratingTablemap<int, Rating*>이 될했습니다. 하나의 클래스 변수에 대해 typedef를 사용하는 것은 다소 모순 된 것처럼 보입니다.

rating은 클래스 변수이지만 두 함수 모두에서 임시 홀더로만 사용하는 것 같습니다. 이것이 의도 된 사용이라면 두 함수에서 지역 변수를 사용하는 것이 낫습니다.

delete지도에 넣는 객체는 Rating입니다. 지도에 Rating 개체가 있어야한다면 개체 수명/메모리 관리 관점에서 std::map<int, Rating>이 더 쉬워 져서 수동으로 삭제하지 않아도됩니다. Rating은 기본 호출로 설계된 것으로 나타나지 않으며, 값 클래스입니다. 어드레스는 다음 삽입 후 맵에서 발견되지

+0

안녕하세요, 의견을 보내 주셔서 감사합니다. 사실 나는 repTable을 하나의 글로벌 제품으로 만들고 fHandInfo를 로컬 제품으로 만들고 싶었지만 제대로하지 못했습니다. (1) 내가 등급 *을 사용하고 'new'를 사용하여 메모리를 할당하려는 경우 등급 *에서 메모리를 해제하는 좋은 방법은 무엇입니까? (2) 이러한 기능을 개별적으로 사용할 때 segfault 명령을 실행할 수있는 충돌의 진정한 이유는 무엇입니까? 감사합니다. –

+0

잘 _undefined behavior_ 의미는 무엇이든 일어날 수 있음을 의미합니다. 그래서 당신은 잘못된 것을 할 수는 있지만, 나쁜 영향을 똑바로 보지 못할 수도 있습니다. 특정 구현에서, 빈 컨테이너에 대한 최종 반복자는 삽입 후 역 참조 할 때 나쁜 일이 발생하는 곳을 가리 키지 않을 수 있습니다. 그러나, 당신은 이것에 의지 할 수 없기 때문에 당신은 그것이 한때는 운 좋았을뿐입니다. –

+0

당신이'new'로 할당 한 객체는 그 객체를 가리키는 포인터에서'delete' 연산자를 사용하여 정확히 한번 삭제되어야합니다. –

2
it = repTable.find(address); 
if (it == repTable.end()){ 
cout << "Adding New Entry for (repTable) "<< address <<endl; 
rating = new Rating(); 
repTable[address] = rating; 
} 
(it->second)->updateRep(behaviour); 

// 반복자 it 자동 새로 삽입 소자 // 포인트 않는다. 따라서 (it-> second)는 UB입니다.

당신은 코드를 조금 수정할 수 있습니다

:

Rating* rating = NULL; 
map<int, Rating*>::iterator it = repTable.find(address); 
if (it == repTable.end()) 
{ 
rating = new Rating(); 
repTable[address] = rating; 
} 
else 
{ 
rating = it->second; 
} 

rating-> updateRep (동작을);

0

보통 Seg 오류는 할당되지 않은 개체에 액세스하려고하기 때문에 발생합니다.

코드에서 IF() 블록 내에서 생성자를 호출하고 있습니다.

if (it == repTable.end()){ 
    cout << "Adding New Entry for (repTable) "<< address <<endl; 
    rating = new Rating(); 
    repTable[address] = rating; 
} 

repTable [주소]에 액세스하려고하면 개체가 없으므로 즉석 예외가 발생합니다.

catch 블록에 넣고 예외 세부 사항을 인쇄 해보십시오. 그러면 어떤 구조가 문제를 일으키는 지에 대한 자세한 정보를 얻을 수 있습니다.

+1

그러나'std :: map :: operator []'는 적절한 요소가 존재하지 않으면 요소를 삽입하고 객체의 value 부분에 대한 참조를 반환합니다. –

+0

나는 콜렉션의 모든 원소가 null이 아니고 실제로 null 포인터 인 원소에 대해 메소드를 호출하려고하는 일반적인 경우를 생각했다. –

1

segfault와 약간 관련이 없지만 예제가 올바르게 작동하지 않는 문제가 있습니다. 주 함수에서 address을 선언하고 사용하기 전에 정의하지 마십시오. 첫 번째 실행에

 
int main() { 
    int address;  
    RepSys repsys; 
    while (address != 0) 
    { 
// ... 
    } 

는 컴파일러에 따라, 당신은 address의 값이 무엇인지 모른다. 처음에는 segfault에 예제를 만들 수 없었습니다. 컴파일러가 0에서 주소를 초기화하고 루프를 건너 뛰고 종료하기 때문에 예제를 얻을 수 없었습니다.

변수를 사용하기 전에 초기화해야합니다.