2011-12-11 5 views
11

의 내가const 구성원이있는 구조체의 벡터입니까?

#include <string> 
#include <vector> 
using namespace std; 

struct Student 
{ 
    const string name; 
    int grade; 
    Student(const string &name) : name(name) { } 
}; 

어떻게하고, 학생들의 벡터를 보관하지 있다고 가정 해 봅시다?

int main() 
{ 
    vector<Student> v; 

    // error C2582: 'operator =' function is unavailable in 'Student' 
    v.push_back(Student("john")); 
} 

도 할 수있는 방법이 있습니까, 아니면 대신 그들 각각에 힙에있는 모든 학생들을 할당하고 포인터를 저장해야?

+0

이 내용은 VC 2010에서 컴파일 및 링크 된 것으로 보입니다. 환경에 대한 자세한 정보를 제공 할 수 있습니까? 이 컴파일 오류를 재생산하는 완벽한 테스트 케이스입니까? – DRH

+0

@DRH : 저는 VC 2008에 있습니다. 죄송합니다. 그리고 네, 전체 테스트 케이스입니다. – Mehrdad

+0

다른 오퍼레이션에서는 할당 연산자가 필요하지만'push_back'이 그 요구 사항을 가질 수있는 가능한 이유는 생각할 수 없다. 다시 한번 구현이 'Assignable' 요구 사항을 확인하는 것일 수도있다. –

답변

7

수 없습니다. 귀하의 유형이 표준 컨테이너에 대한 "할당 가능"요구 사항을 위반합니다.

ISO/IEC 14882 : 2003 23.1 [lib.container.requirements]/3 :

CopyConstructible 유형 (20.1.3)의 요구 사항을 충족해야합니다 이러한 구성 요소에 저장된 개체의 유형, Assignable 유형의 추가 요구 사항.

테이블

64 (Assignable 요구) 표 64

T 용기를 인스턴스화하는데 사용되는 타입이고, tT 값이고, u는 (아마도 const의 값) T.

표현 : t = u; 반환 유형 : T; 사후 조건 : tstd::vector 해당 파괴 할 선택하고 모든 경우에 건설 복사,하지만 선정 된 계약이 아니다 수 u 이론적으로

에 해당합니다. 재 할당이 필요하지 않은 경우 vector::operator=vector::assign과 같이 포함 된 유형의 할당 연산자를 사용하면 훨씬 효율적입니다.

+0

아 ... 그럼 아무 것도 지정하지 않아도 지정할 수 있어야합니까? 그걸 몰랐어. – Mehrdad

+0

@Philipp : 사실, 벡터는 재 할당 할 때 아무 것도 지정하지 않습니다. 일반적으로 새 범위를 복사 또는 이동하여 작성한 다음 이전 범위를 삭제합니다. –

+0

흠 ... 왜'vector'가 복사 할당을 수행합니까? 'operator ='를 사용하는 대신 복사 생성 + 파괴를 할 수 없습니까? – Mehrdad

8

간단한 대답은 다음과 같습니다. 할 수 없습니다. const 멤버 변수가 있으면 컴파일러에서 기본 복사 할당 연산자를 제공 할 수 없습니다. 그러나 std::vector이 제공하는 작업 중 많은 작업이 할당을 필요로하므로 (공용) 복사 할당 연산자가 필요합니다.

옵션은 다음과 같습니다

  1. nameconst을 확인합니다.
  2. 자신의 복사 할당 연산자를 작성하고 const 구성원을 "복사"하는 방법을 생각하십시오.
1

벡터 요소는 const 멤버이기 때문에 Student 구조체가 아닌 복사 할 당할 수 있어야합니다. const string name 대신 string name을 사용하십시오. 특정 요구 사항이 없으면 클래스의 상수 멤버가 거의 유용하지 않습니다. 멤버에 대한 변경을 방지하려면 비공개로 설정하고 공용 getter 함수를 추가하십시오.

3

vector은 종종 요소를 이동해야합니다.push_back()을 호출 할 때마다 벡터를 확장해야 할 때마다 메모리를 다시 할당하여 인접한 모든 요소를 ​​새 공간에 복사합니다. 또한 또는 remove() 요소를 호출하는 경우 요소를 이동해야합니다. vector에 대해 요소를 모두 복사 할 수 있어야한다는 것을 모두 할 수 있어야합니다. 즉, 벡터에 저장하는 유형에 할당 연산자가 정의되어 있어야합니다.

일반적으로 클래스를 정의하면 컴파일러에서 해당 클래스의 할당 연산자를 생성합니다. 그러나 컴파일러가이를 수행 할 수없는 경우가 있습니다. 이러한 경우 중 하나는 클래스에 상수 멤버가있는 경우입니다 (pointers-to-const는 괜찮습니다).

귀하의 경우 문제는 const string name입니다. 컴파일러가 operator=()을 생성하지 못하게하여 실제로 요소에서 직접 할당을 사용하지 않아도 vector이 컴파일되지 않도록합니다.

하나의 솔루션은 비 const로 name을 만드는 것입니다. 다른 하나는 의미가있는 어떤 식 으로든 자신의 Student::operator=()을 작성하는 것입니다. 세 번째 방법은 지적한대로 객체 벡터가 아닌 포인터 벡터를 사용하는 것입니다. 하지만 할당과 할당 해제를 처리해야합니다.

P. 컴파일러가 operator=을 생성 할 수없는 다른 경우는 클래스에 참조 인 멤버가있는 경우입니다.

관련 문제