代码之家  ›  专栏  ›  技术社区  ›  Bernard

为什么不能将转发声明用于std::vector?

  •  23
  • Bernard  · 技术社区  · 17 年前

    如果我创建这样的类:

    // 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 在这件事上,他的错误信息很有启发性。

    8 回复  |  直到 17 年前
        1
  •  32
  •   fyzix    13 年前

    不管T是什么,一个std::vector实例都有一个固定的大小,因为它只包含一个指向T的指针,正如其他人之前所说的那样。但是vector的构造函数取决于具体的类型。您的示例无法编译,因为A()尝试调用向量的ctor,而在不知道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的用户只需要知道a,而不需要知道B:

    // main.cpp
    #include "A.h"
    
    int main()
    {
        A a; // compiles OK
    }
    
        2
  •  31
  •   Curt Hagenlocher    17 年前

    编译器需要知道“B”有多大才能生成适当的布局信息。如果相反,你说 std::vector<B*> ,那么编译器就不需要知道B有多大,因为它知道指针有多大。

        3
  •  5
  •   Josh    17 年前

    要实例化A::v,编译器需要知道B的具体类型。

    如果您试图最小化“包含的行李”的数量以提高编译时间,那么您可以做两件事,这两件事实际上是互不相同的:

    1. 使用指向B的指针
    2. 使用轻便的 proxy 到B
        4
  •  3
  •   MSalters    17 年前

    需要的不仅仅是B的大小。例如,在可能的情况下,现代编译器将使用memcpy来加快向量拷贝的速度。这通常是通过部分专门化元素类型的POD属性来实现的。从转发声明中你无法判断B是否为POD。

        5
  •  3
  •   Raslanove    11 年前

    正如fyzix所说,转发声明不起作用的原因是内联构造函数。即使是空构造函数也可能包含大量代码,比如非POD成员的构造。在您的例子中,您有一个要初始化的向量,如果不完全定义它的模板类型,就无法初始化它。

    析构函数也是如此。向量需要模板类型定义来告诉销毁它所持有的实例时要调用什么析构函数。

    http://www.chromium.org/developers/coding-style/cpp-dos-and-donts

        6
  •  1
  •   Greg Rogers    17 年前

    无论您是使用向量还是尝试实例化一个B,这都无关紧要。实例化需要对象的完整定义。

        7
  •  0
  •   ReinstateMonica3167040 urvashi bhagat    9 年前

    老兄,你在举例 std::vector 类型不完整。不要碰forward声明,只需将构造函数的定义移动到 .cpp 文件

        8
  •  -12
  •   Brad Wilson    17 年前

    无法使用转发声明的原因是B的大小未知。

    编辑: