sourcecode

정확히 어떻게 std::string_view가 conststd::string&보다 빠릅니까?

copyscript 2023. 5. 29. 11:05
반응형

정확히 어떻게 std::string_view가 conststd::string&보다 빠릅니까?

std::string_view C++17에 도달했고 대신 그것을 사용하는 것이 널리 추천됩니다.const std::string&.

그 이유 중 하나는 성능입니다.

누가 어떻게 정확하게 설명해줄 수 있나요? std::string_viewconst std::string&매개 변수 유형으로 사용할 경우(발신자에게 사본이 만들어지지 않았다고 가정합니다.)

std::string_view몇 가지 경우에는 더 빠릅니다.

첫째번.std::string const&가 데터가다있합니다에 .std::string배열이 a 리고원시 C 열이아닌, achar const*C API에 됩니다.std::vector<char>역직렬화 엔진 등에 의해 생산됩니다. (보다 긴 )std::string구현)은 메모리 할당을 방지합니다.

void foo( std::string_view bob ) {
  std::cout << bob << "\n";
}
int main(int argc, char const*const* argv) {
  foo( "This is a string long enough to avoid the std::string SBO" );
  if (argc > 1)
    foo( argv[1] );
}

에할당 않다습니지에서는 .string_view케이스, 하지만 만약에.foo을 가져갔습니다.std::string const&신에대 string_view.

두 번째 정말 큰 이유는 복사본 없이도 서브스트링으로 작업할 수 있기 때문입니다. 문자열을 분석한다고 합니다.으로 구문 하면,std::string노드의 이름이나 값을 저장하는 각 구문 분석 노드는 2gb 문자열에서 로컬 노드로 원본 데이터를 복사합니다.

대신에, 만약 당신이 그것을 해석한다면.std::string_views, 노드는 원본 데이터를 참조합니다.이를 통해 수백만 개의 할당을 절약하고 구문 분석 중 메모리 요구 사항을 절반으로 줄일 수 있습니다.

당신이 얻을 수 있는 속도는 그야말로 터무니없는 것입니다.

" 수 .string_view.

의사결정의 중요한 부분은 사용함으로써 무엇을 잃는가 하는 것입니다.std::string_view많지는 않지만, 그것은 대단한 것입니다.

당신은 암묵적인 null 종료를 잃게 됩니다. 그것이 바로 그것입니다. 문자열이 terminator가 된다면, 를 null terminator로 합니다.std::string한 번은 현명할 수도 있습니다.터미네이터가 한 것으로 알려져 C 이 공급될되지 않는 에는 따서라코드에터미필가요것한으터려로있고알져소있다니습수이수할행다등을문음것에예면공않버서퍼자열이하상로으지되을급스네일타스▁a▁take▁thus▁maybe▁is▁fed▁your있,다▁ifator따니습수라▁a▁code할수▁termin▁or행▁and▁you,-▁from서▁null▁c다을음▁need▁known▁buffers▁don▁strings▁to▁like▁the드면코에▁null▁sourced하예▁expecttstd::string const&그렇지 않을 경우std::string_view.

한다면std::string_view더 화려한 이) 인 약만로 null을 하는 것조차 제거한다는 플래그가 있었습니다.std::string const&.

복용하는 경우가 있습니다.std::stringconst& 다최 보다 최적입니다.std::string_view호출 후 문자열 복사본을 무한정 소유해야 하는 경우 by-value를 사용하는 것이 효율적입니다.SBO 사례(할당 없이 몇 개의 문자 복사본만 복제)에 포함되거나 힙 할당 버퍼를 로컬로 이동할 수 있습니다.std::string의 과부하가 두개과하있음가부의있음▁having.std::string&&그리고.std::string_view속도는 더 빠를 수 있지만, 약간의 경우 코드 블롯이 발생할 수 있습니다(모든 속도 향상 비용이 발생할 수 있음).


◦ 작은 버퍼 최적화

² 실제 사용 사례.

string_view가 성능을 향상시키는 한 가지 방법은 접두사와 접미사를 쉽게 제거할 수 있다는 것입니다.후드 아래에서 string_view는 단순히 접두사 크기를 어떤 문자열 버퍼에 대한 포인터에 추가하거나 바이트 카운터에서 접미사 크기를 뺄 수 있습니다. 이는 보통 빠른 속도입니다. 반면에 std::: string은 substers와 같은 작업을 할 때 바이트를 복사해야 합니다(이렇게 하면 버퍼를 소유하는 새 문자열을 얻을 수 있습니다.그러나 대부분의 경우 복사하지 않고 원래 문자열의 일부만 가져오려고 합니다.)예:

std::string str{"foobar"};
auto bar = str.substr(3);
assert(bar == "bar");

std::string_view 포함:

std::string str{"foobar"};
std::string_view bar{str.c_str(), str.size()};
bar.remove_prefix(3);
assert(bar == "bar");

업데이트:

저는 실수를 추가하기 위해 매우 간단한 벤치마크를 작성했습니다.저는 멋진 구글 벤치마크 라이브러리를 사용했습니다.벤치마크된 기능은 다음과 같습니다.

string remove_prefix(const string &str) {
  return str.substr(3);
}
string_view remove_prefix(string_view str) {
  str.remove_prefix(3);
  return str;
}
static void BM_remove_prefix_string(benchmark::State& state) {                
  std::string example{"asfaghdfgsghasfasg3423rfgasdg"};
  while (state.KeepRunning()) {
    auto res = remove_prefix(example);
    // auto res = remove_prefix(string_view(example)); for string_view
    if (res != "aghdfgsghasfasg3423rfgasdg") {
      throw std::runtime_error("bad op");
    }
  }
}
// BM_remove_prefix_string_view is similar, I skipped it to keep the post short

결과.

6 "(x86_64 리눅스, gcc 6.2,"-O3 -DNDEBUG"):

Benchmark                             Time           CPU Iterations
-------------------------------------------------------------------
BM_remove_prefix_string              90 ns         90 ns    7740626
BM_remove_prefix_string_view          6 ns          6 ns  120468514

두 가지 주요 이유가 있습니다.

  • string_view이 필요하지 .
  • string_view 전달됩니다.

슬라이스의 장점은 다음과 같습니다.

  • 와 함께 사용할 수 있습니다.char const*또는char[]하지 않고 사용할 수 .
  • 여러 조각과 하위 조각을 할당하지 않고 기존 버퍼에 넣을 수 있습니다.
  • 하위 문자열은 O(N)가 아니라 O(1)입니다.
  • ...

전체적으로 성능이 향상되고 일관성이 향상됩니다.


값을 전달하는 것은 또한 별칭 관계 때문에 참조를 전달하는 것보다 이점이 있습니다.

구체적으로, 당신이 할 일이 있을 때.std::string const&매개 변수. 참조 문자열이 수정되지 않는다는 보장은 없습니다.따라서 컴파일러는 각 호출 후 문자열의 내용을 불투명한 메서드(데이터 포인터, 길이 등)로 다시 가져와야 합니다.

면에반을 할 때, 통할때를은 과통때입니다.string_view값에 의해 컴파일러는 현재 스택(또는 레지스터)에서 길이와 데이터 포인터를 수정할 수 있는 다른 코드가 없음을 정적으로 결정할 수 있습니다.결과적으로 함수 호출 간에 "캐시"할 수 있습니다.

그것이 할 수 있는 한 가지는 건설하는 것을 피하는 것입니다.std::string: 로종문자에서암null경개체우의는변되환로:

void foo(const std::string& s);

...

foo("hello, world!"); // std::string object created, possible dynamic allocation.
char msg[] = "good morning!";
foo(msg); // std::string object created, possible dynamic allocation.

std::string_view기본적으로 단지 포장지일 뿐입니다.const char*그리고 패스const char* 더 을 의미합니다.const string&(또는)const string*), 는 다음과 같은

string* -> char* -> char[]
           (   string    )

분명히 상수 인수를 전달하기 위해 첫 번째 포인터는 불필요합니다.

p.s. 사이의 한 가지 실질적인 차이std::string_view그리고.const char*그럼에도 불구하고 string_sys는 null-termination(기본 제공 크기)이 필요하지 않으며, 이를 통해 더 긴 문자열을 임의로 인플레이스 스플라이싱할 수 있습니다.

언급URL : https://stackoverflow.com/questions/40127965/how-exactly-is-stdstring-view-faster-than-const-stdstring

반응형