2014-12-30 4 views
7

죄송합니다. 제목이 혼란 스럽다면, 간단한 문장으로 쉽게 작성할 수 없습니다. 어쨌든, 문제는 내가 직면하고있어 :개인 생성자 및 정적 배열 자체가있는 클래스

// header: 
class SomeThing 
{ 
private: 
    SomeThing() {} // <- so users of this class can't come up 
        // with non-initialized instances, but 
        // but the implementation can. 

    int some_data; // <- a few bytes of memory, the default 
        // constructor SomeThing() doesn't initialize it 
public: 
    SomeThing(blablabla ctor arguments); 

    static SomeThing getThatThing(blablabla arguments); 

    static void generateLookupTables(); 
private: 

    // declarations of lookup tables 
    static std::array<SomeThing, 64> lookup_table_0; 
    static SomeThing lookup_table_1[64]; 
}; 

getThatThing 기능은 조회 테이블에서 인스턴스를 반환하기위한 것입니다. 나는 수업 시간에 공공의 ctor의 SomeThing()을 추가하지 않으면

// in the implementation file - definitions of lookup tables 

std::array<SomeThing, 64> SomeThing::lookup_table_0; // error 

SomeThing Something::lookup_table_1[64]; // <- works fine 

난 그냥하는 std::arraySomething의를 사용할 수 없습니다. 예전 스타일의 배열에서도 잘 작동하며, 배열을 정의하고 SomeThing::generateLookupTables() 함수로 채울 수 있습니다. 외관상으로는 std::array<SomeThing, 64> 유형에는 생성자가 없습니다. 그것을 작동시키는 방법에 대한 아이디어, 아니면이 개념을위한 더 나은 구조?

============= 편집 =======

friend std::array<SomeThing, 64> 접근 방식은 좋은 생각처럼 보이지만 :

사용하는 것입니다 다른 장소의 배열에서도 마찬가지입니다. 이 클래스가 외부 사용자에게 항상 일정한 불변 조건을 유지하도록 보장하고 싶습니다. 이 친숙한 배열을 사용하면 실수로 SomeThing의 초기화되지 않은 배열을 만들 수 있습니다.

또한, 룩업 테이블은 다소 복잡한 과정을 사용하여 생성되며, std::array<SomeThing, 64> SomeThing::lookup_table_0(some value)

+0

클래스가 움직일 수 있다면'std :: vector'를 사용해보십시오. 움직이지 않으면'std :: deque'가 여전히 작동한다고 생각합니다. – Brian

+0

이 클래스 정의가 잘못 구성되어 있는지, 표준 컨테이너가 완전한 유형으로 만 인스턴스화되어야하는지 궁금합니다. (그리고이 문제는 자체의 템플릿에서 오는 정적 멤버가 포함 된 클래스로 인해 발생합니다.) –

+0

매트 : 표준 컨테이너가 헤더에 아직 구현되지 않았지만 구현에만 있습니다. –

답변

4

용액 :

std::array<SomeThing, 64> SomeThing::lookup_table_0 {{ }}; 

참고 here 설명 같이 {{}}가 요구된다 GCC에서 경고없이 std::array 값을 초기화. = {}{}은 정확하지만 gcc는 경고합니다.

솔루션의 핵심은 초기화 도구가 있어야한다는 것입니다.


용어 확인 : 먼저 모든 개체가 C++로 초기화됩니다. 여기에는 세 가지 형식이 있습니다. , 값은입니다. "초기화되지 않은"객체가 없습니다. 명시적인 이니셜 라이저가없는 객체는 이라고하며 기본값은으로 초기화됩니다. 어떤 경우에는 객체의 멤버 변수가 불확실 할 수도 있습니다 ("쓰레기").

초기화자가없는 버전의 문제점은 무엇입니까? 첫째, std::array<SomeThing, 64>의 생성자는 std::array<SomeThing, 64> x; 선언이 SomeThing에 대한 액세스 가능한 기본 생성자가 없기 때문에 std::array<SomeThing, 64> x; 선언이 잘못 작성되어으로 삭제 된 것으로 정의 된 입니다.

즉, std::array<SomeThing, 64>에 대한 기본 생성자를 사용하려고 시도하는 코드는 차례대로 형식이 잘못되었습니다. 정의 :

std::array<SomeThing, 64> SomeThing::lookup_table_0; 

기본 생성자를 사용하려고 시도하므로 부적절합니다. 그러나 일단 이니셜 라이저를 도입하면 std::array의 기본 생성자는 더 이상 작동하지 않습니다. std::array집합체이므로 집계 초기화이 발생하여 암시 적으로 생성 된 생성자를 우회합니다. (사용자가 선언 한 생성자가 있다면 더 이상 집계가되지 않습니다.)

An initializer for a static member is in the scope of the member’s class

리스트 초기화의 정의가 여기 { SomeThing() }-{ } 변환 :

초기화와 버전 때문에 [dcl.init]/13 (n3936)로 작동한다.

+0

) "error : missing initializer member 'std :: array :: _ M_elems'[-Werror = missing-field-initializers] " –

+0

@ Jarod42가 수정되었습니다. –

+0

다른 해결책'lookup_table_0 (SomeThing()}'과 본질적으로 같습니다. 초기화되지 않은 값과 값으로 초기화되는 것 사이에는 차이가 있습니다. 어쨌든, 지금 당장은 구식 배열로 유지할 생각입니다. –

4

생성자는 개인이기 때문에, std::array는 사용할 수 없습니다 같이 인라인 당 할 수 없습니다.

SomeThingfriend class std::array<SomeThing, 64>;을 추가하여 생성자에 액세스 할 수 있습니다.

std::array<SomeThing, 64> SomeThing::lookup_table_0{ 
    SomeThing(blablabla_ctor_arguments), .. 
}; 

편집 : 당신은 당신의 이동이 있거나 사용할 수 생성자를 복사하는 경우도, 할 수

:

대안은 배열의 요소를 초기화하는 데 사용할 수있는 public 생성자를 사용하는 것입니다

std::array<SomeThing, 64> SomeThing::lookup_table_0{ SomeThing() }; 

전체 배열이 기본값으로 초기화됩니다.

+0

Thx,하지만 알다시피, 그것은 개인 생성자를 노출시킬 것입니다. 질문에 내 편집을 참조하십시오. –

+0

@ BuellaGábor : 마법 해결책을 찾은 것 같습니다 :) – Jarod42

+0

와우, 영리합니다. 내 생각에, 실제로 인스턴스를 생성하고 초기화되지 않은 가비지 메모리로 남겨두고 나머지 63 개의 가비지 메모리를 만듭니다. 어떤 종류의 바보 같지만 잘, 기술적으로 "작동". –

5

std::array<SomeThing, 64> 클래스는 인스턴스 정의를 시도 할 때 private 기본 생성자에 대한 액세스 권한을 분명하게 가지고 있지 않습니다. 당신은 SomeThing의 정의에

friend class std::array<SomeThing, 64>; 

를 추가하여에게 필요한 액세스 권한을 부여 할 수 있습니다.