COW basic_string
는 C ++ 11 이상에서 금지됩니까?
에 관해서
” C ++ 11이 COW 기반 구현을 인정하지 않는다는 것이 맞 std::string
습니까?
예.
에 관해서
” 그렇다면이 제한은 새로운 표준 (어디)의 어딘가에 명시 적으로 명시되어 있습니까?
거의 직접적으로 COW 구현에서 문자열 데이터의O ( n ) 물리적 복사가 필요한 여러 작업에 대한 지속적인 복잡성의 요구 사항에 의해.
예를 들어, 멤버 함수의 경우
auto operator[](size_type pos) const -> const_reference;
auto operator[](size_type pos) -> reference;
… COW 구현에서 ¹ 문자열 값 공유를 해제하기 위해 문자열 데이터 복사를 트리거하는 C ++ 11 표준은
C ++ 11 §21.4.5 / 4 :
” 복잡성 : 일정한 시간.
… 이것은 그러한 데이터 복사를 배제하고 따라서 COW.
C ++ 03에 의해 COW 구현을 지원 하지 이러한 일정 복잡성 요구 사항을 가지고, 그리고 특정 제한 조건에 의해 호출 수 operator[]()
, at()
, begin()
, rbegin()
, end()
, 또는 rend()
즉, 문자열 항목을 참조 무효화 참조, 포인터와 반복자에에 가능하게 발생할을 COW 데이터 복사. 이 지원은 C ++ 11에서 제거되었습니다.
COW는 C ++ 11 무효화 규칙을 통해서도 금지됩니까?
글을 쓰는 시점에 해결책으로 선택되고 크게 찬성되어 분명히 믿어지는 또 다른 답변에서 다음과 같이 주장됩니다.
” COW 문자열의 경우 non-를 호출 const
operator[]
하려면 복사 (및 참조 무효화)가 필요합니다. 이는 위의 [C ++ 11 §21.4.1 / 6] 단락에서 허용하지 않습니다. 따라서 C ++ 11에서 COW 문자열을 갖는 것은 더 이상 합법적이지 않습니다.
이 주장은 다음 두 가지 측면에서 부정확하고 오해의 소지가 있습니다.
const
항목 이 아닌 접근 자만 COW 데이터 복사를 트리거해야 함을 잘못 나타냅니다 .
그러나 const
항목 접근자는 클라이언트 코드가 COW 데이터 복사를 트리거 할 수있는 작업을 통해 나중에 무효화 할 수없는 참조 또는 포인터를 형성 할 수 있도록 허용하기 때문에 데이터 복사를 트리거해야합니다.
- COW 데이터 복사로 인해 참조 무효화가 발생할 수 있다고 잘못 가정합니다.
그러나 올바른 구현에서 COW 데이터 복사, 문자열 값 공유 해제는 무효화 될 수있는 참조가 있기 전에 수행됩니다.
올바른 C ++ 11 COW 구현이 basic_string
어떻게 작동 하는지 보려면 이를 무효화하는 O (1) 요구 사항이 무시 될 때 문자열이 소유권 정책간에 전환 할 수있는 구현을 생각해보십시오. 문자열 인스턴스는 Sharable 정책으로 시작합니다. 이 정책이 활성화되면 외부 항목 참조가있을 수 없습니다. 인스턴스는 고유 정책으로 전환 할 수 있으며, .c_str()
(적어도 내부 버퍼에 대한 포인터를 생성하는 경우) 호출과 같이 항목 참조가 잠재적으로 생성 될 때 그렇게해야합니다 . 값의 소유권을 공유하는 여러 인스턴스의 일반적인 경우에는 문자열 데이터 복사가 수반됩니다. 고유 정책으로 전환 한 후 인스턴스는 할당과 같은 모든 참조를 무효화하는 작업을 통해서만 다시 공유 가능으로 전환 할 수 있습니다.
따라서 COW 문자열이 배제되었다는 대답의 결론은 정확하지만 제공된 추론은 정확하지 않으며 오해의 소지가 있습니다.
이 오해의 원인이 C ++ 11의 부록 C에있는 비 규범 적 메모라고 생각합니다.
C ++ 11 §C.2.11 [diff.cpp03.strings], 약 §21.3 :
변경basic_string
사항 : 요구 사항은 더 이상 참조 카운트 문자열을 허용하지 않습니다
. 이유 : 무효화는 참조 카운트 문자열과 미묘하게 다릅니다. 이 변경은이 국제 표준의 행동 (원문)을 정규화합니다.
원래 기능에 미치는 영향 : 유효한 C ++ 2003 코드는이 국제 표준에서 다르게 실행될 수 있습니다.
여기서 근거 는 C ++ 03 특수 COW 지원을 제거하기로 결정한 주요 이유를 설명합니다 . 이 근거, 그 이유 는 표준이 COW 구현을 효과적으로 허용하지 않는 방법 이 아닙니다 . 이 표준은 O (1) 요구 사항을 통해 COW를 허용하지 않습니다.
요컨대, C ++ 11 무효화 규칙은 COW 구현을 배제하지 않습니다 std::basic_string
. 그러나 그들은 g ++의 표준 라이브러리 구현 중 적어도 하나에있는 것과 같이 합리적으로 효율적인 무제한 C ++ 03 스타일 COW 구현을 배제합니다. 특별한 C ++ 03 COW 지원 const
은 무효화에 대한 미묘하고 복잡한 규칙을 희생 하면서 특히 항목 접근자를 사용하여 실질적인 효율성을 허용했습니다 .
"첫 번째 호출"COW 지원을 포함하는
C ++ 03 §21.3 / 5 :
" a의 요소를 참조 참조 포인터 및 반복자 basic_string
시퀀스는 그 다음 사용에 의해 무효화 될 수도 basic_string
개체 :
- 비 멤버 함수의 인수로 swap()
(21.3.7.8), operator>>()
(21.3.7.9)와 getline()
(21.3. 7.9).
—의 인수로 basic_string::swap()
.
— 호출 data()
및 c_str()
멤버 함수.
- 비 호출 const
제외 멤버 함수 operator[]()
, at()
, begin()
, rbegin()
, end()
, 및 rend()
.
-의 형태를 제외하고 상기 용도 중 임의의 이후 insert()
및 erase()
반복자 반환 비 처음 호출 const
멤버 함수 operator[]()
, at()
, begin()
, rbegin()
,end()
, 또는 rend()
.
이러한 규칙은 너무 복잡하고 미묘해서 많은 프로그래머가 정확한 요약을 제공 할 수 있을지 의심 스럽습니다. 나는 할 수 없었다.
O (1) 요구 사항이 무시되면 어떻게됩니까?
예를 들어 C ++ 11 일정 시간 요구 사항 operator[]
이 무시되면 COW for basic_string
는 기술적으로는 가능하지만 구현하기 어려울 수 있습니다.
COW 데이터 복사없이 문자열 내용에 액세스 할 수있는 작업은 다음과 같습니다.
- 를 통한 연결
+
.
- 를 통해 출력
<<
.
basic_string
표준 라이브러리 함수에 인수로 사용 .
후자는 표준 라이브러리가 구현 특정 지식과 구성에 의존하도록 허용되기 때문입니다.
또한 구현은 COW 데이터 복사를 트리거하지 않고 문자열 내용에 액세스하기위한 다양한 비표준 기능을 제공 할 수 있습니다.
가장 복잡한 요인은 C ++ 11에서 basic_string
항목 액세스가 데이터 복사 (문자열 데이터 공유 해제)를 트리거해야하지만 던지지 않아야한다는 것입니다 (예 : C ++ 11 §21.4.5 / 3 " Throws : Nothing."). 따라서 일반 동적 할당을 사용하여 COW 데이터 복사를위한 새 버퍼를 만들 수 없습니다. 이를 해결하는 한 가지 방법은 메모리를 실제로 할당하지 않고도 예약 할 수있는 특수 힙을 사용한 다음 문자열 값에 대한 각 논리적 참조에 필요한 양을 예약하는 것입니다. 이러한 힙에서 예약 및 예약 해제는 일정 시간 O (1) 일 수 있으며 이미 예약 한 양을 할당하면noexcept
. 표준의 요구 사항을 준수하기 위해이 접근 방식을 사용하려면 고유 한 할당 자당 하나의 특별한 예약 기반 힙이 있어야합니다.
참고 :
¹ const
항목 접근자는 클라이언트 코드가 데이터에 대한 참조 또는 포인터를 얻을 수 있도록 COW 데이터 복사를 트리거합니다. 이는 예를 들어 const
항목 이 아닌 접근 자 에 의해 트리거되는 이후 데이터 복사에 의해 무효화되는 것이 허용되지 않습니다 .