libc ++의 vector <bool> :: const_reference가 bool이 아닌 이유는 무엇입니까?


92

섹션 23.3.7 클래스 vector<bool>[vector.bool], 단락 1은 다음과 같이 설명합니다.

template <class Allocator> class vector<bool, Allocator> {
public:
    // types:
    typedef bool              const_reference;
    ...

그러나이 프로그램은 libc ++를 사용할 때 컴파일되지 않습니다.

#include <vector>
#include <type_traits>

int
main()
{
    static_assert(std::is_same<std::vector<bool>::const_reference, bool>{}, "?");
}

또한 C ++ 표준은이 사양에서 C ++ 98로 거슬러 올라갈 때까지 일관성이있었습니다. 그리고 libc ++는 libc ++가 처음 도입 된 이후로이 사양을 지속적으로 따르지 않았습니다.

이 부적합의 동기는 무엇입니까?

답변:


99

이 확장에 대한 동기는 준수 프로그램에 의해 감지되어 부적합 하며 참조 (const 및 기타)와 관련하여 vector<bool>더 유사 하게 동작 하도록 만드는 것 vector<char>입니다.

소개

1998 년부터 vector<bool>"그렇지 않은 용기"로 조롱되었습니다. 최초의 LWG 문제 중 하나 인 LWG 96 이 토론을 시작했습니다. 17 년이 지난 오늘날에는 vector<bool>거의 변함이 없습니다.

이 백서 에서는의 동작이의 vector<bool>다른 모든 인스턴스화와 어떻게 다른지 에 대한 몇 가지 특정 예제를 살펴보고 vector일반 코드를 손상시킵니다. 그러나 동일한 문서는 vector<bool>제대로 구현 된 경우 매우 좋은 성능 속성 이 가질 수있는 길이에 대해 설명 합니다.

요약 : vector<bool>나쁜 컨테이너가 아닙니다. 실제로 매우 유용합니다. 이름이 좋지 않습니다.

돌아가다 const_reference

위에서 소개하고 여기자세히 설명 했듯이 나쁜 점 vector<bool>은 일반 코드에서 다른 vector인스턴스화 와 다르게 동작한다는 것 입니다. 다음은 구체적인 예입니다.

#include <cassert>
#include <vector>

template <class T>
void
test(std::vector<T>& v)
{
    using const_ref = typename std::vector<T>::const_reference;
    const std::vector<T>& cv = v;
    const_ref cr = cv[0];
    assert(cr == cv[0]);
    v[0] = 1;
    assert(true == cv[0]);
    assert(cr == cv[0]);  // Fires!
}

int
main()
{
    std::vector<char> vc(1);
    test(vc);
    std::vector<bool> vb(1);
    test(vb);
}

표준 규격은 어설 표시된 것을 말한다 // Fires!트리거하지만 경우에만 test으로 실행됩니다 vector<bool>. 로모그래퍼 실행하면 vector<char>(또는 vector외에 bool적절한 기본이 아닌이 때 T할당), 시험은 통과한다.

libc ++ 구현은 vector<bool>제네릭 코드에서 다르게 동작 할 때의 부정적인 영향을 최소화하려고했습니다 . 한 가지는 이것이 확인하는 것입니다 달성했다 프록시 참조를 지정된처럼, 당신은 그것을 통해 할당 할 수 없습니다 것을 제외하고. 즉, libc ++에서 기본적 으로 해당 비트의 복사본이 아니라 내부의 비트에 대한 포인터 입니다.vector<T>::const_referencevector<T>::referencevector<T>::const_referencevector

libc ++에서 위의 내용 testvector<char>vector<bool>.

비용은 얼마입니까?

단점은 질문에 표시된 것처럼이 확장이 감지 될 수 있다는 것입니다. 그러나 실제로이 별칭의 정확한 유형에 관심이있는 프로그램은 거의 없으며 동작에 관심이있는 프로그램이 더 많습니다.

이 부적합의 동기는 무엇입니까?

libc ++ 클라이언트에게 일반 코드에서 더 나은 동작을 제공하고 아마도 충분한 현장 테스트 후에 전체 C ++ 산업의 향상을 위해 향후 C ++ 표준에 대한이 확장을 제안하십시오.

이러한 제안은 bit_vector현재와 ​​거의 동일한 API를 vector<bool>갖지만 const_reference여기 에서 논의 된 것과 같은 몇 가지 업그레이드 가 포함 된 새 컨테이너 (예 :)의 형태로 제공 될 수 있습니다. vector<bool>전문화 의 지원 중단 (및 최종 제거)이 이어집니다 . bitset또한이 부서에서 약간의 업그레이드 (예 : add const_reference및 반복기 집합)를 사용할 수도 있습니다 .

돌이켜 보면이에 즉, bitset이다 vector<bool>(어떤이로 변경해야한다 bit_vector등, - 또는 무엇이든) array이다 vector. 그리고 비유는 우리가 얘기 여부를 성립한다고 bool는 AS value_typevectorarray.

libc ++의 확장으로 시작된 C ++ 11 및 C ++ 14 기능의 여러 예가 있습니다. 이것이 표준이 진화하는 방식입니다. 실제로 입증 된 긍정적 인 현장 경험은 강력한 영향을 미칩니다. 표준 담당자는 기존 사양을 변경할 때 보수적입니다. 정확하게 추측하고 있다고 확신하는 경우에도 추측은 국제적으로 인정받는 표준을 발전시키기위한 위험한 전략입니다.


1
질문 : @EricNiebler의 프록시 반복자에 대한 최근 초안 제안이 어떻게 든 libc ++ 확장을 합법화하고 vector<bool>더 일류 기반에 놓을 수 있습니까?
TemplateRex

비고 : 나는이 선호하는 것 vector_bool<Alloc>하고는 array_bool<N>의 (랜덤 액세스 프록시 모든 비트를 반복 반복자 포함) 포장 버전을 나타내는 vector<bool, Alloc>등을 array<bool, N>. 그러나 bitset<N>(그리고 그것은 사촌입니다 boost::dynamic_bitset<Alloc>) 다른 추상화, 즉 std::set<int>. 내가 가지고 싶습니다 그래서, 말 bit_array<N>bit_vector<Alloc> 적절한 양방향 반복기를 가진 bitset 프랜차이즈의 후계자가 (모든 비트가 아닌 1 비트를 반복). 이것에 대한 당신의 생각은 무엇입니까?
TemplateRex

5
프록시 반복기에 대한 초안 제안 vector<bool>은 표준을 준수하는 임의 액세스 컨테이너를 만들 것 입니다. vector<bool>좋은 생각 이 아닙니다 . :-) 나는 하워드에 동의합니다. 다른 이름으로 불렸어야했습니다.
Eric Niebler

1
libc ++ 확장을 옵트 아웃하고 엄격하게 준수하는 동작을 얻을 수있는 방법이없는 이유는 무엇입니까? (저는 적합성을 기본값으로 만드는 것이 아니라 이식 가능한 코드를 작성할 수 있도록 libc ++의 확장을 비활성화하는 방법 일뿐입니다). 아시다시피 저는 과거에 libc ++ 튜플 확장에 물 렸고 최근에는 bitset :: const_reference 확장에 물 렸습니다.
gnzlbg

5
@gnzlbg : libc ++의 초기 개발을 위해 한정된 양의 경제적 및 시간적 자원을 사용할 수있었습니다. 그 후 구현은 모든 단일 사용자를 행복하게 만들지 못할 운명이었습니다. 사용 가능한 리소스가 주어지면 행복한 사용자 수를 최대화하고 전체 C ++ 커뮤니티에 대한 이익을 최대화하기 위해 엔지니어링 트레이드 오프가 이루어졌습니다. 경험에 대해 죄송합니다. 당신이 잘못 실행 한 튜플 확장은 현재 C ++ 1z 작업 문서에 있습니다. 그 문제에 대해 당신은 많은 사람들이 이익을 얻을 수 있도록 무의식적으로 희생했으며 그 많은 사람들은 당신에게 감사의 빚을졌습니다.
Howard Hinnant 2015-08-14
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.