문제

STD :: 문자열의 "+"연산자에 대한 걱정을 표현하는 소수의 사람들과 다양한 해결 방법을 들었습니다. 이것들 중 정말 필요한 것이 있습니까? 그렇다면 C ++에서 현을 연결하는 가장 좋은 방법은 무엇입니까?

도움이 되었습니까?

해결책

실제로 효율성이 필요하지 않으면 추가 작업은 아마도 그만한 가치가 없습니다. Operator += 대신 사용하면 더 나은 효율성을 가질 것입니다.

이제 면책 조항 후에, 나는 당신의 실제 질문에 답할 것입니다 ...

STL 문자열 클래스의 효율성은 사용중인 STL의 구현에 따라 다릅니다.

당신은 할 수 있습니다 효율성을 보장합니다 그리고 더 큰 통제력이 있습니다 C 내장 기능을 통해 수동으로 연결을 수행하여 자신을 직접 수행합니다.

운영자+가 효율적이지 않은 이유 :

이 인터페이스를 살펴보십시오.

template <class charT, class traits, class Alloc>
basic_string<charT, traits, Alloc>
operator+(const basic_string<charT, traits, Alloc>& s1,
          const basic_string<charT, traits, Alloc>& s2)

각 +이후에 새 개체가 반환되는 것을 볼 수 있습니다. 즉, 새로운 버퍼가 매번 사용됩니다. 엑스트라 + 작업을하는 경우 효율적이지 않습니다.

더 효율적으로 만들 수있는 이유 :

  • 당신은 대의원을 신뢰하는 대신 효율성을 보장하고 있습니다.
  • STD :: 문자열 클래스는 문자열의 최대 크기에 대해서는 아무것도 모르거나 얼마나 자주 연결되는지에 대해 아무것도 모릅니다. 이 지식을 가질 수 있으며이 정보를 기반으로하는 일을 할 수 있습니다. 이로 인해 재 할당이 줄어 듭니다.
  • 버퍼를 수동으로 제어하므로 이런 일이 발생하지 않을 때 전체 문자열을 새 버퍼에 복사하지 않도록 할 수 있습니다.
  • 훨씬 더 효율적인 힙 대신 버퍼에 스택을 사용할 수 있습니다.
  • String + Operator는 새 문자열 객체를 생성하여 새 버퍼를 사용하여 반환합니다.

구현을위한 고려 사항 :

  • 문자열 길이를 추적하십시오.
  • 문자열의 끝과 시작에 대한 포인터를 유지하거나 시작을 시작하고 시작 + 길이를 오프셋으로 사용하여 문자열의 끝을 찾으십시오.
  • 문자열을 저장하는 버퍼를 입력하고 데이터를 재 할당 할 필요가 없도록 충분히 커지십시오.
  • 문자열의 끝을 찾기 위해 문자열의 길이를 반복 할 필요가 없으므로 strcat 대신 strcpy를 사용하십시오.

로프 데이터 구조 :

실제로 빠른 연결이 필요한 경우 a를 사용하는 것을 고려하십시오 로프 데이터 구조.

다른 팁

전에 최종 공간을 예약 한 다음 버퍼와 함께 Append Method를 사용하십시오. 예를 들어, 최종 문자열 길이가 백만자가 될 것으로 기대합니다.

std::string s;
s.reserve(1000000);

while (whatever)
{
  s.append(buf,len);
}

나는 그것에 대해 걱정하지 않을 것입니다. 루프에서 수행하면 문자열은 항상 메모리를 Prealloce를 통해 재 할당을 최소화합니다. operator+= 이 경우. 그리고 수동으로 그렇게한다면, 이와 같은 것 이상

a + " : " + c

컴파일러가 일부 반환 값 사본을 제거 할 수 있더라도 임시를 생성합니다. 그것은 연속적으로 호출 되었기 때문입니다 operator+ 참조 매개 변수가 이름 지정된 개체를 참조하는지 또는 하위에서 임시로 반환되는지 여부는 모릅니다. operator+ 기도. 나는 먼저 프로파일을 제공하지 않기 전에 걱정하지 않을 것입니다. 그러나 그것을 보여주는 모범을 보이자. 우리는 먼저 바인딩을 명확하게하기 위해 괄호를 소개합니다. 명확성에 사용되는 함수 선언 후에 인수를 직접 넣었습니다. 그 아래에, 나는 결과적인 표현이 무엇인지 보여줍니다.

((a + " : ") + c) 
calls string operator+(string const&, char const*)(a, " : ")
  => (tmp1 + c)

이제 그 추가로 tmp1 표시된 인수와 함께 Operator++에 대한 첫 번째 호출에 의해 반환 된 것입니다. 컴파일러가 정말 영리하다고 가정하고 반환 값 사본을 최적화합니다. 그래서 우리는 a 그리고 " : ". 이제 이런 일이 발생합니다.

(tmp1 + c)
calls string operator+(string const&, string const&)(tmp1, c)
  => tmp2 == <end result>

다음과 비교하십시오.

std::string f = "hello";
(f + c)
calls string operator+(string const&, string const&)(f, c)
  => tmp1 == <end result>

임시 및 명명 된 문자열에 동일한 함수를 사용하고 있습니다! 그래서 컴파일러 가지다 인수를 새로운 줄에 복사하고 그에 부여하고 본체에서 반환합니다. operator+. 그것은 일시적인 기억을 취할 수 없으며 그것에 추가 할 수는 없습니다. 표현이 클수록 더 많은 문자열 사본을 수행해야합니다.

다음 비주얼 스튜디오와 GCC는 C ++ 1X를 지원합니다. 의미론을 움직입니다 (보완 시맨틱을 복사하십시오) 및 rvalue 참조 실험 첨가. 이를 통해 매개 변수가 임시를 참조하는지 여부를 파악할 수 있습니다. 위의 모든 것이 사본없이 하나의 "추가 된 파이프 라인"으로 끝나기 때문에 그러한 추가가 놀랍도록 빠릅니다.

병목 현상으로 밝혀지면 여전히 할 수 있습니다.

 std::string(a).append(" : ").append(c) ...

그만큼 append 호출은 논쟁을 부여합니다 *this 그런 다음 자신에 대한 참조를 반환하십시오. 따라서 임시를 복사하지 않습니다. 또는 또는 operator+= 사용할 수 있지만 우선 순위를 고정하려면 못생긴 괄호가 필요합니다.

대부분의 응용 프로그램에서는 중요하지 않습니다. 코드를 작성하고 + 운영자가 정확히 어떻게 작동하는지 알지 못하고 명백한 병목 현상이되면 문제를 해결하십시오.

.NET System.Strings와 달리 C ++의 std :: 문자열 ~이다 변이 가능하므로 다른 방법을 통해 간단한 연락을 통해 구축 할 수 있습니다.

아마도 std :: stringstream 대신?

그러나 나는 당신이 아마 당신이 그것을 유지 가능하고 이해할 수있게 유지하고, 실제로 문제가 있는지 확인하기 위해 프로필을 유지해야한다는 감정에 동의합니다.

~ 안에 불완전한 C ++, Matthew Wilson은 a 동적 모든 부품을 연결하기 전에 하나의 할당을 갖기 위해 최종 문자열의 길이를 미리 컴파일하는 문자열 연결 장치. 우리는 또한 연주함으로써 정적 연결자를 구현할 수 있습니다. 표현식 템플릿.

이러한 종류의 아이디어는 Stlport std :: 문자열 구현에서 구현되었습니다.이 구현은이 정확한 해킹으로 인해 표준을 준수하지 않습니다.

std::string operator+ 새 문자열을 할당하고 매번 두 개의 피연산자 문자열을 복사합니다. 여러 번 반복하면 비싸게됩니다. O (n).

std::string append 그리고 operator+= 반면에 문자열이 자라야 할 때마다 용량을 50% 씩 부딪칩니다. 메모리 할당 및 복사 작업의 수를 크게 줄입니다 (log n).

작은 문자열의 경우 중요하지 않습니다. 큰 문자열이 있다면 벡터 나 다른 컬렉션에서 부품으로 보관하는 것이 좋습니다. 알고리즘을 추가하여 하나의 큰 문자열 대신 이러한 데이터 세트로 작동하도록합니다.

복잡한 연결을 위해 STD :: Ostringstream을 선호합니다.

대부분의 것들과 마찬가지로, 그렇게하는 것보다 무언가를하지 않는 것이 더 쉽습니다.

큰 문자열을 GUI에 출력하려면, 출력하는 모든 것이 큰 문자열보다 더 나은 조각으로 문자열을 처리 할 수있는 것일 수 있습니다 (예 : 텍스트 편집기에서 텍스트를 연결하십시오 - 일반적으로 라인을 별도로 유지합니다. 구조).

파일로 출력하려면 큰 문자열을 만들고 출력하지 않고 데이터를 스트리밍하십시오.

느린 코드에서 불필요한 연결을 제거하면 연결이 더 빨리 필요하다는 것을 알지 못했습니다.

배열 크기와 할당 된 바이트 수를 추적하는 클래스에 캡슐화 된 간단한 문자 배열이 가장 빠릅니다.

요령은 처음에 하나의 큰 할당을하는 것입니다.

~에

https://github.com/pedro-vicente/table-string

벤치 마크

Visual Studio 2015의 경우 x86 디버그 빌드, C ++ std :: string에 대한 변하기 개선.

| API                   | Seconds           
| ----------------------|----| 
| SDS                   | 19 |  
| std::string           | 11 |  
| std::string (reserve) | 9  |  
| table_str_t           | 1  |  

결과 문자열에서 공간을 사전 할당하는 경우 최상의 성능.

template<typename... Args>
std::string concat(Args const&... args)
{
    size_t len = 0;
    for (auto s : {args...})  len += strlen(s);

    std::string result;
    result.reserve(len);    // <--- preallocate result
    for (auto s : {args...})  result += s;
    return result;
}

용법:

std::string merged = concat("This ", "is ", "a ", "test!");
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top