2017-09-04 23 views
-1

파일 경로 정규화 기능에 이상한 문제가 있습니다. 완전히 이해하지 못하고 고칠 수있는 문제가 있습니다 (C++에서는 노련하지도 않습니다).vector.erase()가 SIGABRT를 실행하는 이유는 무엇입니까?

/** 
* Converts any path (e.g. /a/d/../b/.//c/) to absolute /a/b/c format. 
* @param path Any valid path beginning with/
* @return Path in absolute /a/b/c format. 
*/ 
static std::string normalizePath(std::string path) 
{ 
    if (path == "/") 
     return "/"; 

    if (path[0] != '/') // full relative paths not supported due to lack of context 
     return ""; 

    std::vector<std::string> segments = strsplit(path, '/'); 
    while (segments[0] == "." || segments[0] == "..") 
     segments.erase(segments.begin()); 

    for (int i = 0; i < segments.size(); i++) 
    { 
     if (segments[i] == "." || segments[i].empty()) 
      segments.erase(segments.begin() + (i--)); 
     else if (segments[i] == "..") 
      segments.erase(segments.begin() + (--i), segments.begin() + (i+2)); // SIGABRT 
    } 

    std::string r; 
    for (int i = 0; i < segments.size(); i++) 
     r += "/" + segments[i]; 

    return r; 
} 

그것은 대부분의 입력이 잘 작동하지만 ("/"을 반환하도록되어) 입력 "https://stackoverflow.com/a/.."이가 표시 줄에서 SIGABRT와 충돌합니다.

필자는 현재 요소와 이전 요소를 삭제하려고하고 있지만 분명히 가정이 잘못되었습니다.

가상 경로로 작업 중이므로 모든 파일 시스템에 대한 호출을 원하지 않기 때문에 realpath()을 사용하는 것을 꺼려합니다.

왜 내 코드가 충돌합니까? 의도 한대로 작동하게하려면 어떻게해야합니까? 는 액세스가 서로에 대해 unsequenced되는 문맥 회 i 액세스 때문에

+2

https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom – user0042

+1

동일한 문에서'--i'와'i + 2'를 사용하면 문제가 있는지 묻습니다. 'i + 2'가 범위를 벗어날 수 있고 함수 매개 변수의 평가 순서가 지정되지 않았다는 것은 말할 필요도 없습니다. –

+1

@ user0042 std :: remove는 특정 값을 가진 요소를 제거하는 것으로 보이지만 특정 인덱스가있는 요소를 제거하려고합니다. –

답변

1

이 선은, 동작 보증되지 :

segments.erase(segments.begin() + (--i), segments.begin() + (i+2)); 

계산 순서를 지정하기 때문에, 그리고 적용 측의 순 효과를 알 수없는 경우, segments.begin() + (i+2)은 iterator 지난 벡터의 끝으로 평가할 수 있습니다.

erase에서 복귀 한 후 사전 감소없이 i의 값을 사용하고 --을 적용함으로써이 문제를 해결할 수

else if (segments[i] == "..") { 
    segments.erase(std::next(segments.begin(), i-1), std::next(segments.begin(), i+1)); 
    --i; 
} 

참고 : 위의 코드 반복기에 번호를 추가하는 대신 std::next 사용.