C ++ 11은 vector <const T>를 허용합니까?


82

컨테이너 요구 사항이 C ++ 03에서 C ++ 11로 변경되었습니다. C ++ 03에는 포괄적 인 요구 사항 (예 : 벡터에 대한 복사 구성 및 할당 가능성)이 있었지만 C ++ 11은 각 컨테이너 작업에 대한 세부적인 요구 사항을 정의합니다 (섹션 23.2).

따라서 할당이 필요하지 않은 특정 작업 만 수행하는 한 (construction 및 push_back이러한 작업) 벡터에 복사 생성 가능하지만 할당 할 수없는 유형 (예 : const 멤버가있는 구조)을 저장할 수 있습니다. ; insert아닙니다).

내가 궁금한 것은 : 이것이 표준이 이제 허용한다는 의미 vector<const T>입니까? 나는 그것이 안되는 이유를 보지 못했다- const T, const 멤버가있는 구조처럼, 복사는 구성 할 수 있지만 할당 할 수없는 유형이다-그러나 나는 무언가를 놓쳤을 수있다.

(내가 뭔가를 놓쳤다 고 생각하게 만드는 부분 중 하나는 인스턴스화하려고하면 gcc 트렁크가 충돌하고 화상을 입지 vector<const T>vector<T>T에 const 멤버가있는 곳에서는 괜찮습니다 ).

답변:


55

아니요, 할당 자 요구 사항에 따르면 T는 "비상 수, 비 참조 객체 유형"이 될 수 있습니다.

상수 객체로 구성된 벡터로는 많은 일을 할 수 없습니다. 그리고 a const vector<T>는 어쨌든 거의 동일합니다.


수년이 지난 후에도이 빠르고 더러운 대답은 여전히 ​​댓글과 투표를 끌어들이는 것 같습니다. 항상 위로는 아닙니다. :-)

따라서 적절한 참조를 추가하려면 :

내가 종이에 가지고있는 C ++ 03 표준의 경우 [lib.allocator.requirements] 섹션의 표 31에 다음과 같이 나와 있습니다.

T, U any type

어떤 유형도 실제로 작동 하지 않았습니다 .

따라서 다음 표준 인 C ++ 11 은 [allocator.requirements]와 이제 표 27의 초안 에서 다음과 같이 말합니다 .

T, U, C any non-const, non-reference object type

이것은 내가 위에서 처음 기억에서 쓴 것과 매우 유사합니다. 이것은 또한 질문에 관한 것입니다.

그러나 C ++ 14 ( draft N4296 )에서는 이제 표 27에 다음과 같이 표시됩니다.

T, U, C any non-const object type

아마도 참조가 결국 객체 유형이 아니기 때문일까요?

이제 C ++ 17 ( 초안 N4659 )에서는 다음과 같은 표 30이 있습니다.

T, U, C any cv-unqualified object type (6.9)

따라서 const배제 될뿐만 아니라 volatile. 어쨌든 오래된 뉴스 일 것입니다.


현재 바로 아래에있는 Howard Hinnant의 직접 정보를 참조하십시오 .


43
결론 : 우리는 const T를 담을 수있는 컨테이너를 디자인하지 않았습니다. 그리고 우연히 그렇게하는 것에 정말 가까워졌습니다. 내가 아는 한, 현재 고정 지점은 address기본 할당 자에있는 오버로드 된 멤버 함수 쌍입니다 . T가 const이면이 두 오버로드는 동일한 서명을 갖습니다. 이를 수정하는 쉬운 방법 std::allocator<const T>은 오버로드 중 하나 를 전문화 하고 제거하는 것입니다.
Howard Hinnant 2011-08-05

4
@ HighCommander4 : 나는 긍정적이지 않습니다. libc ++에서는 협력 할당 자로 벡터 (비어 있지 않더라도)를 생성 할 수 있습니다. 나는 그것으로 (상수가 아닌) 아무것도 할 수 없습니다. 그것이 당신의 "작품"에 대한 정의에 맞는지 잘 모르겠습니다. 또한 무의식적으로 확장 프로그램을 이용하고있는 경우에도 긍정적이지 않습니다. 확실하게하려면이 질문에 더 많은 시간을 투자해야합니다. 나는 전에 시간에 그렇게 투자했지만 그것은 몇 년 전이었고 그 동안 많은 것들이 바뀌 었습니다. 작동한다면위원회 측에서 의도 한 것이 아닙니다.
Howard Hinnant 2011-08-05

1
@ 하워드 : 할 수있는 데 어떤 기술적 장애물도 생각할 수 없습니다 push_back. 그러나 설계 상 허용되지 않는 경우에는하지 않는 것이 좋습니다. 나는 단지 궁금했다.
HighCommander4 2011-08-05

8
캐시는 종종 변경 불가능한 객체의 변경 가능한 컨테이너이며 정렬 된 벡터는 종종 맵의 대안이므로 const 객체의 벡터가 거의 사용되지 않는다는 데 동의하지 않습니다.
Chris Oldwood

9
부끄러운 일입니다. 나는 std::vector<const T>그것이와 매우 유사하기 때문에 정확히 사용 const std::vector<T>했지만 그것을 보유하고있는 클래스에 대한 후자의 부정적인 의미는 없었다. 사실, std::vector<const T>내가 사용하는 대부분의 경우 의미 론적으로 정확히 필요한 것 vector입니다. 이제 나는 const그것이 제공하는 신뢰성과 함께 떨어 뜨려야 합니다.
바이올렛 기린

30

최신 정보

받아 들여진 (그리고 정확한) 대답 아래에서 나는 2011 년에 다음과 같이 언급했습니다.

결론 : 우리는 const T. 나는 그것에 대해 약간의 생각을했지만. 그리고 우연히 그렇게하는 것에 정말 가까워졌습니다. 내가 아는 한, 현재의 부착 점은 오버로드의 쌍의 address경우 : 기본 할당에서 멤버 함수 T이며 const,이 두 오버로드가 같은 서명을해야합니다. 이를 수정하는 쉬운 방법 std::allocator<const T>은 오버로드 중 하나 를 전문화 하고 제거하는 것입니다.

다가오는 C ++ 17 초안에서 우리는 이제 합법화 한 것처럼 보이며 실수로vector<const T> 그렇게했다고 믿습니다 . :-)

P0174R0 은에서 address과부하를 제거합니다 std::allocator<T>. P0174R0std::allocator<const T>근거의 일부로 지원에 대해 언급하지 않습니다 .

보정

아래의 주석에서 TC는 address오버로드가 제거 되지 않고 더 이상 사용되지 않는다는 것을 올바르게 지적합니다 . 내 잘못이야. 더 이상 사용되지 않는 멤버는 std::allocator이 정의 된 20.10.9에 표시되지 않지만 대신 섹션 D.9로 강등됩니다. 나는 이것을 게시 할 때 이러한 가능성에 대해 D 장을 스캔하는 것을 무시했습니다.

수정 해 주셔서 감사합니다. 나는이 오해의 소지가있는 답변을 삭제하는 것을 고려했지만, 아마도 내가했던 것과 같은 방식으로 다른 사람이 사양을 잘못 읽지 않도록이 수정 사항을 남겨 두는 것이 가장 좋습니다.


7
꽤 재미 있습니다! (이제 우리는 그것에 대해 정말 조용히해야합니다. 그리고 아무도 눈치 채지 못한 채 C ++ 17로 들어가도록 놔두세요 :))
HighCommander4

하지 않습니다 할당 자 요구 사항 테이블은 여전히 크게 그것을 금지? 그럼에도 불구하고 P0174R2 (투표 된 개정판)는 제거하지 않고 address.
TC

@TC : 당신이 절대적으로 옳습니다. 수정 해 주셔서 감사합니다.
Howard Hinnant

그래서 c ++ 2x는 마침내 허용 할 것입니다 vector<const T>:)
MM

1
"요점 : 우리는 콘테이너가 const T를 유지하도록 설계하지 않았습니다."라는 대답은 콘테이너가 "const T"를 유지하는 것이 목표라고 가정합니다. 그러나 사용자의 목표는 컨테이너에 대한 작업을 제한하는 것이라고 주장 할 수 있습니다. 예를 들어 'back ()'은 컨테이너에 포함 된 내용에 관계없이 "const T &"를 반환합니다.
Hans Olsson 2016 년

8

우리는 이미 이것에 대해 아주 좋은 답변을 가지고 있지만, 할 수있는 것과 할 수없는 것을 보여주기 위해 좀 더 실용적인 답변으로 기여하기로 결정했습니다.

그래서 이것은 작동하지 않습니다.

vector<const T> vec; 

이유를 이해하려면 다른 답변을 읽으십시오. 그리고 짐작 하셨겠지만이 방법도 작동하지 않습니다.

vector<const shared_ptr<T>> vec;

T더 이상 없습니다 constvector들고 shared_ptr들,하지 T이야.

반면에 이것은 작동 합니다.

vector<const T *> vec;
vector<T const *> vec;  // the same as above

그러나이 경우 const는 포인터 자체 (벡터가 저장하는 것)가 아니라 가리키는 객체입니다. 이것은 다음과 같습니다.

vector<shared_ptr<const T>> vec;

괜찮습니다.

그러나 const표현식의 끝에 넣으면 이제 포인터가로 바뀌 const므로 다음은 컴파일되지 않습니다.

vector<T * const> vec;

약간 혼란 스럽지만 동의하지만 익숙해집니다.


4

다른 답변을 보완하는 또 다른 방법은 다음을 사용하는 것입니다.

vector<unique_ptr<const T>> vec;

vec항목에 대한 소유권 만있는 것을 강제하려는 경우 . 또는 항목을 이동하는 동적 기능을 원하는 경우 항목을 vec이동합니다.

뾰족한 OUT으로, 포인터의 const의미가 혼동 될 수 있지만 shared_ptrunique_ptr수 없습니다. const unique_ptr<T>는 const 포인터이고 unique_ptr<const T>예상대로 const pointee입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.