std::Vector에 전방 선언을 사용할 수 없는 이유는 무엇입니까?
문제
다음과 같은 클래스를 생성하면:
// 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 수하물의 양을 최소화하려는 경우 실제로 서로 변형된 두 가지 작업을 수행할 수 있습니다.
- B에 대한 포인터 사용
- 가벼운 것을 사용하세요 대리 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년대...;)