2010-05-26 8 views
54

나는 불변의 문자열에 대해 최근에 herehere을 읽었으며, 왜 D이 불변의 문자열을 선택했는지에 관해서 몇 가지 내용을 읽었습니다. 많은 이점이있는 것 같습니다. 불변의 문자열 대 std :: 문자열

  • 은 하찮게 대부분의 사용 사례에 안전
  • 더 안전
  • 더 많은 메모리를 효율적으로 스레드.
  • 저렴한 문자열 (토큰 화와 슬라이스)

말할 것도없고 대부분의 새로운 언어가 불변 문자열, D2.0, 자바, C#을, 파이썬, 불변의 문자열에서 등

겠습니까 C++ 혜택?

이러한 모든 장점을 갖는 불변의 문자열 클래스를 C++ (또는 C++ 0x)로 구현할 수 있습니까?


갱신 :

불변의 문자열 const_stringfix_str 두 시도가있다. 어느 쪽도 반세기 만에 업데이트되지 않았습니다. 그들은 심지어 사용됩니까? const_string이 왜 그것을 향상시키지 않았습니까?

+42

BlueRaja에서 작성한 매우 정교하고 설득력있는 주장입니다. – peterchen

+5

글쎄, BlueRaja는 실제로 논쟁을하지 않았습니다. 모두 분명히 지적했기 때문입니다. 그러나 C++은 가정을 찾기 위해 불변의 문자열을 사용하는 순수 주의자 시도에 너무 많은 하이브리드 언어 일 수 있습니다. 이것은 물론 언어 자체보다는 C++ 문화에 대해 더 많이 말합니다. –

+5

이의 제기! Ruby의 문자열은 변경할 수 없습니다! – Notinlist

답변

22

: 네, 꽤 C에 대한 불변의 문자열 라이브러리 ++ 싶습니다

  • .
  • 아니요, std :: string이 변경되지 않습니다.

(표준 라이브러리 기능으로) 정말 가치가 있습니까? 나는 말하지 않을 것이다. const를 사용하면 지역적으로 변경할 수없는 문자열을 얻을 수 있으며 시스템 프로그래밍 언어의 기본 특성은 실제로 가변 문자열을 필요로한다는 것을 의미합니다.

+3

C++에서 불변의 문자열에 가장 가까운 것은 두 개의 const 포인터가있는 "span"클래스입니다. 하나는 begin과 하나는 끝에 대한 포인터입니다. 메모리를 관리하지는 않았지만 일반적인 유틸리티 기능 (find 등)을 지원했습니다. 결과적으로 파싱에 매우 유용합니다. –

+2

@StevenSudit : 대다수의 대형 프로젝트가 있는데, 일반적으로 'stringref' 또는 이와 유사합니다. –

+2

@MooingDuck 사실입니다. Google은 자사의 [StringPiece] (https://code.google.com/p/re2/source/browse/re2/stringpiece.h)를 호출합니다 –

1
const std::string 

여기 있습니다. 정의되지 않은 동작에 들어가기를 원하지 않는다면 문자열 리터럴도 변경할 수 없습니다.

편집 : 물론 절반 밖에 이야기가 아닙니다. const 문자열 변수는 새로운 문자열을 참조 할 수 없으므로 유용하지 않습니다. C++에서 파이썬 같은 다른 언어에서와 마찬가지로 참조를 재 할당 할 수 없다는 점을 제외하고는 const 문자열에 대한 참조가 가능합니다. 가장 가까운 것은 동적으로 할당 된 문자열에 대한 스마트 포인터입니다. 의견으로

+2

그 이상이 필요합니다. 'std :: string :: replace'가 컴파일 에러가 아닌 수정 된 복사본을 반환하기를 원할 것입니다. – peterchen

+1

@peterchen -> const std :: string orig; const std :: string copy = std :: string (orig) .replace (...); - 불변의 문자열은 무엇이 좋을까요? –

+0

새로운 문자열의 IMHO 할당은 문자열을 변형하고 있으며, 내가 작성한 API의 기억에서이 구조를 취한 방법입니다. 당신이 원하는 것은 실제로 할당 가능한 레퍼런스처럼 들리며 할당 할 수있는 const 문자열을 만드는 것보다 스마트 포인터와 같은 것이 더 나은 대답이라고 생각됩니다. 나는 또한 const std :: string vars가 때때로 유용하다는 것을 발견한다. 그래서 나는 거기에서 달라달라고 부탁해야 할 것이다. –

3

당신은 분명 그 사람이 아닙니다. 사실 Maxim Yegorushkin의 const_string 라이브러리가 있습니다.이 라이브러리는 마음에 넣기 위해 포함시킨 것 같습니다. 그리고 여기 Roland Pibinger의 좀 더 새로운 라이브러리 fix_str이 있습니다. 나는 실행 시간에 전체 문자열 인턴이 얼마나 까다로울 지 확신하지 못한다.하지만 대부분의 장점은 필요할 때 성취 할 수있다.

0

Qt는 copy-on-write와 함께 불변 문자열을 사용합니다.
괜찮은 컴파일러로 얼마나 많은 성능을 얻는 지에 대한 몇 가지 논쟁이 있습니다.

+4

나는 copy-on-write 문자열을 불변이라고 부르지 않을 것이다. 변경할 수없는 문자열은 COW 문자열의 하위 집합입니다. 즉, 모든 문자열과 불변 문자열은 COW 문자열을 처리 할 수 ​​있지만 그 반대는 사실이 아닙니다. COW 문자열을 동시 환경에서 사용할 수있게하는 것은 이러한 추가 기능입니다. –

+0

스레드 안전성을 보장하기 위해 쓰기를 수행 할 때마다 믹스에서 COW를 throw하면 스레드 안전성이 완전히 사라집니다 (라이브러리 자체를 명시 적으로 또는 라이브러리 자체에서 잠글 필요가 있음). –

+0

@David : Qt는 스레드 안전 COW를 사용합니다. 참조 횟수에 대한 원자 정수로 자체 잠금을 수행합니다. – CMircea

0

상수 문자열은 가치 의미론에별로 의미가없고, 공유는 C++의 가장 큰 강점 중 하나가 아닙니다 ...

+1

C#에 값 의미가있는 상수 문자열이 있다고 가정합니다. –

+0

@Steven 어쩌면 우리는 "가치 의미론"을 말할 때 다른 것들에 대해서 이야기하고있을 것입니다. C# 문자열은 투명 레벨의 간접 참조 (참조 의미)를 통해 항상 처리되지만 C++ 문자열은 (값 의미)이 아닙니다. – fredoverflow

+0

아마도. C#에서는 실제 값 형식 (예 : int)이 System.ValueType에서 상속되고 복사본으로 전달되는 반면 참조 형식은 참조로 전달되고 참조는 (일반적으로) 참조로 비교됩니다. C# 문자열은 참조 인 반면, 불변이고 주소가 아닌 내용에 의해 비교된다는 점에서 값 의미를가집니다. C++에서 std :: string은 값이지만 변경할 수있는 버퍼에 대한 참조 (실제로는 포인터)가 들어 있습니다. 따라서 C++ 문자열의 복사본을 전달하면 버퍼를 복제하는 복사 생성자가 호출되지만 const 참조를 전달하면 오버 헤드가 발생하지 않습니다. 그게 더 분명해지기를 바랍니다. –

3

확실한 대답은 없을 것 같습니다. 주관적이기 때문에 — 개인적인 취향 때문에 코드 유형이 가장 자주 다루기 때문에 그렇지 않습니다. (여전히 귀중한 질문입니다.)

메모리가 쌌을 때 변경 불가능한 문자열은 우수합니다. — C++이 개발되었을 때 이것이 사실이 아니었고 C++이 타겟으로하는 모든 플랫폼에서는 그렇지 않았습니다. (제한된 플랫폼의 OTOH는 C++보다 훨씬 일반적인 것처럼 보입니다.)

C++에서 불변 문자열 클래스를 만들 수 있으며 대체로 std::string —과 호환 될 수 있지만 여전히 손실됩니다 전용 최적화 및 언어 기능이있는 내장 문자열 클래스와 비교할 때.

std::string표준 문자열이 가장 좋기 때문에 어떤 문제가 있는지보고 싶지 않습니다. 나는 그것을 거의 사용하지 않는다. std::string에는 내 관점에서 너무 많은 단점이 있습니다 .

+2

'std :: string'이 가장 좋은 표준 문자열이지만, 너무나 많은 단점 때문에 * 사용하는 경우는 거의 없습니다. *, ** ** 당신이 사용하는 것은 무엇입니까? –

+3

10 년 이상의 누적 된 라이브러리, 더 나은 기본 API interop (wchar_t/char 변환 포함) 때문에 'CString' (나를 죽이지 마세요). 그 당시에는 잘 정의 된 copy-on-write가 std :: string의 성능 보장에 비해 이점이 될 것입니다. – peterchen

+0

@peterchen MFC 또는 WTL의 CString? – Mike

7

내 결론은 C++은 const 의미론을 가지고 있기 때문에 불변의 패턴을 요구하지 않는다는 것이다.

Person 클래스가 있고 getName() 메서드를 사용하는 사람의 String name을 반환하는 경우 유일한 변경 사항은 변경 불가능한 패턴뿐입니다. 만약 거기에 없으면 당신은 밤낮으로 당신의 문자열을 clone()해야 할 것입니다. (당신은 전형적인 값 객체가 아니지만 여전히 보호 될 필요가있는 데이터 멤버로해야만합니다.)

C++에는 const std::string& getName() const이 있습니다. 따라서 SomeFunction(person.getName())을 쓸 수 있습니다. void SomeFunction(const std::string& subject)과 같습니다. 사람이 그가 그렇게

  • 기술은 모든 데이터 유형에 적용 할 무료로 복사하고자 할 경우

    • 없음 복사
    • 을 일어나지 않았다, 단지 내가이 스레드에서 대부분의 사람들이 어떻게 발견
  • +4

    수정! 변경 불가능한 문자열은 다중 스레드 프로그램에서 동시성을 처리 할 때 오버 헤드가 없으므로 유용 할 수 있습니다. 그리고 대부분의 경우 문자열을 편집하지 않고 단순히 문자열 만 바꾸면됩니다. – Notinlist

    40

    을 문자열 immutable_string이 무엇인지 이해하지 못합니다. 그것은 단서에 관한 것만이 아닙니다. immutable_string의 실제 성능은 (단일 스레드 프로그램에서도) 성능과 메모리 사용량입니다.

    모든 문자열을 변경할 수 있으며, 모든 문자열이 어떻게 하위 STR 동작을 구현할 수

    class string { 
        char* _head ; 
        size_t _len ; 
    } ; 
    

    과 같이 구현하는 경우, 그 상상? 우리는 char를 복사 할 필요가 없습니다. 우리가해야할 일은 _head과 입니다. 그런 다음 하위 문자열은 소스 문자열과 동일한 메모리 세그먼트를 공유합니다.

    물론 두 개의 데이터 멤버로만 immutable_string을 구현할 수는 없습니다. 실제 구현에는 참조 횟수 (또는 플라이 가중치) 메모리 블록이 필요할 수 있습니다. 이와 같이

    class immutable_string { 
        boost::fly_weight<std::string> _s ; 
        char* _head ; 
        size_t _len ; 
    } ; 
    

    대부분의 경우 메모리와 성능이 모두 기존 문자열보다 좋을 것입니다. 특히 수행중인 작업을 알고있을 때 더욱 그렇습니다.

    물론 C++은 불변 문자열로부터 이점을 얻을 수 있습니다. Cubbi가 언급 한 boost::const_stringfix_str을 확인했습니다. 그것들은 제가 말하고자하는 것이어야합니다.

    -1

    문자열은 Ruby에서 변경할 수 있습니다.

    • $ irb 
      >> foo="hello" 
      => "hello" 
      >> bar=foo 
      => "hello" 
      >> foo << "world" 
      => "helloworld" 
      >> print bar 
      helloworld=> nil 
      

      은 하찮게 안전

    내가 안전 인수를 잊어 경향이 스레드. 스레드로부터 안전하려면 잠금 또는 잠그지 마십시오. C++은 편리한 언어가 아니며 사용자 고유의 규칙을가집니다.

    • 더 안전

    번호는 즉시 포인터를 arithmetics과 주소 공간에 대한 보호되지 않은 액세스 권한을 갖는 경우, 보안 것에 대해 잊어. 무해한 코딩에 대해보다 안전합니다.

    • 대부분의 사용 사례에서 더 효율적인 메모리입니다.

    CPU 집약적 인 메커니즘을 구현하지 않는 한 어떻게 보이지 않습니다. 하나의 아주 좋은 포인트가 될 것

    • 저렴한 문자열 (토큰 화와 슬라이스)

    . 문자열을 수정하면 사본이 생성되는 역 참조가있는 문자열을 참조하여 수행 할 수 있습니다. 토큰 화 및 조각화는 자유롭게되고 돌연변이는 값 비싸게됩니다.

    -4

    C++ 문자열은 스레드로부터 안전하며 모든 불변 개체는 스레드로부터 안전하지만 Java StringBuffer는 C++ string처럼 변경할 수 있으며 둘 다 스레드로부터 안전합니다. 속도에 대해 걱정할 필요가없는 이유는 const 키워드로 메소드 또는 함수 매개 변수를 정의하여 컴파일러에게 해당 문자열이 해당 범위에서 변경되지 않는다는 것을 알려주는 것입니다. 또한 문자열 개체가 필요에 따라 변경 될 수없는 경우, 문자열을 절대적으로 사용해야 할 때 대기합니다. 즉, 다른 문자열을 기본 문자열에 추가 할 때 전체 문자열이 실제로 필요할 때까지 문자열 목록을 보유한 다음 조인됩니다 그 시점에서 함께.

    불변하고 변경 가능한 객체는 찬반 양론의 방법을 제외하고는 내 지식과 동일한 속도로 작동합니다. 상수 프리미티브와 변수 프리미티브는 기계 수준에서 변수가 레지스터 나 메모리 공간에 할당되기 때문에 다른 속도로 이동합니다. 상수는 그 중 아무 것도 필요로하지 않으며 따라서 더 빠릅니다 (또는 적은 작업이 이루어짐). 객체가 아닌 프리미티브에서만 작동합니다.

    1

    변경할 수없는 문자열이 인 경우이면 새 문자열을 만들어야 할 때마다 메모리 관리자가 항상 모든 문자열 참조의 위치를 ​​결정할 수 있습니다.대부분의 플랫폼에서 이러한 기능에 대한 언어 지원은 비교적 저렴한 비용으로 제공 될 수 있지만 이러한 언어 지원 기능이없는 플랫폼에서는 훨씬 더 어렵습니다.

    예를 들어, 불변 문자열을 지원하는 x86 용 파스칼 구현을 설계하려는 경우 문자열 할당자가 모든 문자열 참조를 찾기 위해 스택을 이동할 수 있어야합니다. 그것의 유일한 실행 시간 비용은 일관된 함수 호출 접근법을 요구할 것이다. 꼬리 호출을 사용하지 않고, 모든 리프가 아닌 함수가 프레임 포인터를 유지하도록]. new으로 할당 된 각 메모리 영역에는 문자열이 포함되어 있는지 여부를 나타내는 비트가 있어야하며 문자열이 포함 된 메모리 영역은 메모리 레이아웃 설명자에 대한 인덱스가 있어야하지만 비용은 매우 적습니다.

    GC가 스택을 걷는 테이블이 아닌 경우 포인터 대신 포인터를 사용하고 로컬 변수가 범위에 올 때 코드 생성 문자열 핸들을 사용하여 핸들을 파괴해야합니다 범위를 벗어났습니다. 훨씬 큰 오버 헤드.