std::Vector에 전방 선언을 사용할 수 없는 이유는 무엇입니까?

StackOverflow https://stackoverflow.com/questions/37346

  •  09-06-2019
  •  | 
  •  

문제

다음과 같은 클래스를 생성하면:

// B.h
#ifndef _B_H_
#define _B_H_

class B
{
private:
    int x;
    int y;
};

#endif // _B_H_

다음과 같이 사용하세요.

// main.cpp
#include <iostream>
#include <vector>

class B; // Forward declaration.

class A
{
public:
    A() {
        std::cout << v.size() << std::endl;
    }

private:
    std::vector<B> v;
};

int main()
{
    A a;
}

컴파일할 때 컴파일러가 실패합니다. main.cpp.이제 내가 아는 해결책은 #include "B.h", 그런데 왜 실패했는지 궁금합니다.어느 것도 아니다 g++ 또는 cl의 오류 메시지는 이 문제에 대해 매우 계몽적이었습니다.

도움이 되었습니까?

해결책

컴파일러는 적절한 레이아웃 정보를 생성하기 전에 "B"의 크기를 알아야 합니다.오히려 네가 말했다면 std::vector<B*>, 그러면 컴파일러는 포인터가 얼마나 큰지 알기 때문에 B가 얼마나 큰지 알 필요가 없습니다.

다른 팁

실제로 A의 생성자가 B 유형을 아는 컴파일 단위로 구현된 경우 예제가 빌드됩니다.

std::Vector 인스턴스는 T가 무엇이든 상관없이 고정된 크기를 갖습니다. 이전에 다른 사람들이 말했듯이 T에 대한 포인터만 포함하기 때문입니다.그러나 벡터의 생성자는 구체적인 유형에 따라 다릅니다.A()가 B를 모르면 생성할 수 없는 벡터의 ctor를 호출하려고 하기 때문에 귀하의 예제가 컴파일되지 않습니다.작동하는 방법은 다음과 같습니다.

A의 선언:

// A.h
#include <vector>

class B; // Forward declaration.

class A
{
public:
    A(); // only declare, don't implement here

private:
    std::vector<B> v;
};

A의 구현:

// A.cpp
#include "A.h"
#include "B.h"

A::A() // this implicitly calls vector<B>'s constructor
{
    std::cout << v.size() << std::endl;
}

이제 A의 사용자는 B가 아닌 A만 알면 됩니다.

// main.cpp
#include "A.h"

int main()
{
    A a; // compiles OK
}

A::v를 인스턴스화하려면 컴파일러는 B의 구체적인 유형을 알아야 합니다.

컴파일 시간을 개선하기 위해 #included 수하물의 양을 최소화하려는 경우 실제로 서로 변형된 두 가지 작업을 수행할 수 있습니다.

  1. B에 대한 포인터 사용
  2. 가벼운 것을 사용하세요 대리 B에게

필요한 것은 B의 크기 그 이상입니다.예를 들어 최신 컴파일러에는 가능한 경우 memcpy를 사용하여 벡터 복사 속도를 높이는 멋진 트릭이 있습니다.이는 일반적으로 요소 유형의 POD를 부분적으로 전문화하여 달성됩니다.전방 선언에서는 B가 POD인지 알 수 없습니다.

fyzix가 말했듯이 전방 선언이 작동하지 않는 이유는 인라인 생성자 때문입니다.빈 생성자에도 POD가 아닌 멤버 생성과 같은 많은 코드가 포함될 수 있습니다.귀하의 경우 초기화할 벡터가 있는데, 템플릿 유형을 완전히 정의하지 않으면 초기화할 수 없습니다.

소멸자도 마찬가지다.벡터에는 보유한 인스턴스를 삭제할 때 어떤 소멸자를 호출할지 알려주는 템플릿 유형 정의가 필요합니다.

이 문제를 해결하려면 생성자와 소멸자를 인라인하지 마세요.B가 완전히 정의된 후 어딘가에 별도로 정의하십시오.

자세한 내용은,http://www.chromium.org/developers/coding-style/cpp-dos-and-donts

벡터를 사용하든 B를 인스턴스화하든 상관없습니다.인스턴스화에는 개체의 전체 정의가 필요합니다.

이봐, 당신은 인스턴스화 중이야 std::vector 불완전한 유형입니다.전방 선언을 건드리지 말고 생성자의 정의를 .cpp 파일.

전방 선언을 사용할 수 없는 이유는 B의 크기를 알 수 없기 때문입니다.

귀하의 예에서는 A.h 안에 B.h를 포함할 수 없는 이유가 없습니다. 그렇다면 실제로 해결하려는 문제는 무엇입니까?

편집하다: 이 문제를 해결하는 다른 방법도 있습니다.C/C++ 사용을 중단하세요!때는 바야흐로 1970년대...;)

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top