std :: string의 c_str ()에서 어떤 성능을 기대할 수 있습니까? 항상 일정한 시간?


13

최근에 몇 가지 필요한 최적화를 수행했습니다. 내가하고있는 한 가지는 ostringstreams-> sprintfs를 변경하는 것입니다. 나는 std :: strings를 ac 스타일 배열에 sprintf'ing하고있다.

char foo[500];
sprintf(foo, "%s+%s", str1.c_str(), str2.c_str());

Microsoft의 std :: string :: c_str () 구현은 일정한 시간에 실행됩니다 (내부 포인터 만 반환합니다). libstdc ++는 동일한 작업을 수행하는 것으로 보입니다 . std가 c_str을 보장하지는 않지만 이것을 수행하는 다른 방법을 상상하기는 어렵다는 것을 알고 있습니다. 예를 들어 메모리에 복사 한 경우 버퍼에 메모리를 할당하거나 (STL 계약의 일부가 아닌 파기하기 위해 호출자에게 맡김) 내부 정적에 복사해야하는 경우 버퍼 (아마 스레드 안전하지 않으며 수명에 대한 보장이 없습니다). 따라서 내부적으로 유지 관리되는 null 종료 문자열에 대한 포인터를 반환하는 것이 유일한 현실적인 해결책 인 것 같습니다.

답변:


9

내가 기억한다면, 표준은 string::c_str()만족하는 모든 것을 돌려 줄 수 있습니다 .

  • 끈의 내용과 종료의 내용에 충분히 큰 수납 NULL
  • 주어진 string객체 의 비 const 멤버 가 호출 될 때까지 유효해야합니다.

실제로 이것은 내부 저장소에 대한 포인터를 의미합니다. 반환 된 포인터의 수명을 외부에서 추적 할 수있는 방법이 없기 때문에. 나는 이것이 작은 시간이라고 가정하는 것이 안전하다고 생각합니다.

관련 참고 사항에서 문자열 형식이 성능 제한 인 경우 Boost.Phoenix 와 같은 것이 절대적으로 필요할 때까지 평가를 연기하는 것이 더 좋습니다 .

Boost.Format 결과가 필요할 때까지 내부적으로 형식을 연기한다고 생각하고 형식 문자열을 다시 구문 분석하지 않고도 동일한 형식의 개체를 반복적으로 사용할 수 있습니다.


2
구현에서 널 터미네이터를 추가하기에 충분히 큰 새로운 또는 2 차 내부 버퍼를 작성할 수 있습니다. 비록 c_strCONST 방법 (또는 적어도 CONST 과부하를 갖는다 - I 어느 잊어)이 이렇게하는 이유 일 수 있고, 논리 값을 변경하지 않는다 mutable. 그것은 에서 포인터 휴식 다른 호출을 c_str, 그러한 포인터가 동일한 논리 문자열을 참조해야한다는 점을 제외하고 (그래서 재 할당 할 새로운 이유가 없다 - 이미 널 터미네이터가 있어야합니다) 또는 이미 다른 비에 대한 호출이되어 있어야합니다 -const 메소드 사이.
Steve314

이것이 실제로 유효한 경우 c_str, 재 할당 및 복사에 대한 호출은 O (n) 시간이 될 수 있습니다. 그러나 내가 알지 못하는 표준에 여분의 규칙이있어 이것을 막을 수도 있습니다. 내가 제안하는 이유-호출 c_str이 실제로 일반적인 AFAIK를 의미하는 것은 아니기 때문에 신속하게 확인하는 것이 중요 string하지 않을 c_str수도 있습니다. 우선권을 갖습니다.
Steve314

Boost.Format내부적으로 스트림을 통과하고 내부적으로 sprintf는 다소 큰 오버 헤드로 끝납니다. 문서에 따르면 일반보다 약 8 배 느립니다 sprintf. 성능과 형식 안전성을 원하면을 사용해보십시오 Boost.Spirit.Karma.
Jan Hudec

Boost.Spirit.Karma성능에 대한 유용한 팁이지만 기존 printf스타일 코드 (및 코더) 를 적용하는 데 까다로울 수있는 방법이 크게 다릅니다 . Boost.Format우리의 I / O가 비동기이기 때문에 나는 주로 고착했다 . 그러나 가장 큰 요인은 동료가 일관되게 사용하도록 설득 할 수 있다는 것입니다 (여전히 ostream<<과부하 가있는 모든 유형을 허용합니다 - .c_str()토론을 회피하는 데 도움이 됩니다 ) Karma 성능 수치.
rvalue

23

c ++ 11 표준 (N 3290 버전을 읽고 있습니다)에서 21.4.7.1 장은 c_str () 메소드에 대해 설명합니다.

const charT* c_str() const noexcept; const charT* data() const noexcept;

결과 : [0, size ()]의 각 i에 대해 p + i == & operator와 같은 포인터 p.
복잡성 : 일정한 시간.
요구 사항 : 프로그램은 문자 배열에 저장된 값을 변경하지 않아야합니다.

그렇습니다. 일정한 시간의 복잡성은 표준에 의해 보장됩니다.

방금 c ++ 03 표준을 확인했으며 그러한 요구 사항이 없으며 복잡성을 알려줍니다.


8

이론적으로 C ++ 03은이를 요구하지 않으므로 문자열은 c_str ()이 호출 될 때만 null 종결자가 존재하는 char 배열 일 수 있습니다. 재 할당이 필요할 수 있습니다 (내부 개인 포인터가로 선언 된 경우 const-ness를 위반하지 않음 mutable).

C ++ 11은 더 엄격합니다. 시간 비용이 많이 들기 때문에 재배치를 수행 할 수 없으며 배열은 항상 널을 저장하기에 충분히 넓어야합니다. c_str () 자체는 여전히 " ptr[size()]='\0'"를 수행하여 널이 실제로 존재하도록 보장 할 수 있습니다 . 범위 [0..size())가 변경되지 않기 때문에 배열의 불변성을 위반하지 않습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.