c++ new 為什麼不能為std:: vector使用前向聲明?




vector c++ wiki (7)

如果我這樣創建一個類:

// 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 "Bh" ,但我很好奇,為什麼它失敗。 g++cl的錯誤信息在這個問題上是非常有啟發性的。


Answer #1

無論使用矢量還是嘗試實例化一個B都無關緊要。實例化需要對象的完整定義。


Answer #2

男人,你是一個不完整的類型實例化std::vector 。 不要觸及前向聲明,只要將構造函數的定義移動到.cpp文件即可。


Answer #3

這不僅僅是需要的B的大小。 例如,現代編譯器將會使用memcpy加速矢量拷貝。 這通常通過部分專門化元素類型的POD性來實現。 您無法判斷B是否是前向聲明的POD。


Answer #4

編譯器需要知道“B”有多大才能生成適當的佈局信息。 相反,如果你說std::vector<B*> ,那麼編譯器不需要知道B有多大,因為它知道指針有多大。


Answer #5

為了實例化A :: v,編譯器需要知道B的具體類型。

如果你想盡量減少#included行李的數量,以提高編譯時間,有兩件事你可以做,其實是彼此的變化:

  1. 使用指向B的指針
  2. B使用輕量級代理

Answer #6

實際上,如果A的構造函數是在知道B類型的編譯單元中實現的,那麼您的示例將會生成。

一個std :: vector實例具有一個固定的大小,不管T是什麼,因為它像前面所說的那樣只包含一個指向T的指針。但是vector的構造函數依賴於具體的類型。 你的例子不會編譯,因為A()試圖調用向量的ctor,不能不知道B生成。這是什麼工作:

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的用戶只需要知道A而不是B:

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

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

Answer #7

就像fyzix說的,你的前向聲明不工作的原因是你的內聯構造函數。 即使是一個空的構造函數也可能包含很多代碼,比如構建非POD成員。 在你的情況下,你有一個矢量初始化,你不能完全定義它的模板類型。

析構函數也是一樣。 該向量需要模板類型定義來告訴銷毀它所擁有的實例時調用哪個析構函數。

為了擺脫這個問題,不要內聯構造函數和析構函數。 在B被完全定義之後的某個地方定義它們。

有關更多信息, 請訪問http://www.chromium.org/developers/coding-style/cpp-dos-and-donts





stl