【问题标题】:Declaration of std::vector works with forward declared classes?std::vector 的声明与前向声明的类一起使用吗?
【发布时间】:2016-01-17 17:54:54
【问题描述】:

我有一个像下面这样的头文件-

// abc.hpp
#include <vector>
#include <string>

namespace A 
{
    namespace B 
    {   
        struct abc 
        {   
            std::string _type;
        };  

        using abc_vector = std::vector<abc>;
    }   

}

我在另一个头文件中使用前向声明。

// con.hpp
#include <vector>

namespace A 
{
    namespace B 
    {   
        struct abc; // Forward Declaration
        using abc_vector = std::vector<abc>;
    }   

    namespace C
    {   
        class N
        {   
            public:
                B::abc_vector foo(std::string type);
        };  
    }   
}

真正让我感到困惑的是我的代码可以编译和工作。

如何允许向量声明为不完整类型? 我认为它不应该能够决定 abc 的大小

using abc_vector = std::vector<abc>;

下面是我用来测试头文件的代码。 很奇怪,它可以编译并且运行良好。

#include "con.hpp"
#include "abc.hpp"

#include <iostream>

namespace A
{
    namespace C
    {   
        B::abc_vector N::foo(std::string type)
        {   
            B::abc a;
            a._type = type;

            B::abc_vector d;
            d.push_back(a);
            return d;
        }   
    }   
}

int main()
{
    A::C::N n;
    auto container = n.foo("test");

    for (const auto& i : container)
          std::cout << i._type << ' ';

    return 0;
}

【问题讨论】:

  • “我认为它不应该能够决定 abc 的大小。” 是什么让你认为它需要?
  • 我认为这行得通,因为类型是您在函数中使用它时定义的。
  • 我在这里的答案中读到了它 - [link] (stackoverflow.com/questions/37346/…) 编译器需要知道“B”有多大才能生成适当的布局信息。
  • @badola 提示:std::vector&lt;T&gt; 的大小与T 的大小和向量中的元素数量无关。

标签: c++


【解决方案1】:

代码行

using abc_vector = std::vector<abc>;

std::vector&lt;abc&gt; 引入类型别名。这无论如何都不需要abc 的大小,因为根本没有分配abc 类型的对象。只声明了一个新类型。

B::abc_vector d;

确实需要abc的定义。尽管如此,它仍然有效,因为此时已经定义了 abc,因为已经包含了头文件 abc.hpp


你指的是this answer,在哪里

std::vector<B> v;

“完成”。这和你做的不一样。您刚刚介绍了一个类型别名。 std::vector&lt;B&gt; v; 实际上定义一个变量。因此B的定义是强制性的。


注意

using abc_vector = std::vector<abc>;

等价于

typedef std::vector<abc> abc_vector;

也许这让我们更清楚为什么在编译的这个时间点不需要知道abc 的大小。

【讨论】:

  • 我很好奇你认为B::abc_vector d; 做了什么。
  • 嗯可能是因为第二个示例确实包含abc.hpp。加上这一点,指出这个问题有缺陷,你已经明白了。
  • @LightnessRacesinOrbit 是的,“已经定义”是指已经包含“abc.hpp”并且在那里定义了abc。而B::abc_vector d;std::vector&lt;int&gt; d;,对吧?
  • 不,是std::vector&lt;abc&gt; d;
  • @LightnessRacesinOrbit 哦,废话。
【解决方案2】:

这是一个有趣的话题(至少对我而言)并且适用于其他标准容器。

最初,标准将实例化不完整类型的容器设为未定义行为。然而,实现并没有禁止它。这很可能不是故意的,而只是其中的元素(例如向量)存储在指针引用的内存位置这一事实的副作用。

因此,在实际需要元素之前不需要知道元素的大小 - 在向量的成员函数的实例化期间。

如果您想进一步探索,这里是研究的起点:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4056.html

【讨论】:

  • 感谢@Richard Hodges,这是一个更有说服力的答案。 :) 你能指出更多的文章,我可以在哪里读到它..?
  • 嗯,你的问题让我想起了前段时间在 boost 文档中读到的一些内容。此链接包含相当完整的叙述boost.org/doc/libs/1_55_0/doc/html/container/…
【解决方案3】:

有一个有趣的观察。 GCC5.2CLANG3.6 都编译以下代码。

struct A;

std::vector<A> my_func(); //Definition of my_func is in some CPP file

但是抛出错误

struct A;

std::vector<A> v;

原因是向量的大小不会因它所持有的不同类型而改变。见以下代码sn-p。

struct B{int i; int j;};
struct C{int a,b,c;};

std::vector<B> pp;
std::vector<C> qq;

int main()
{
  std::cout<<sizeof(pp)<<'\n';
  std::cout<<sizeof(qq)<<'\n';
}

输出

24

24

但对于std::vector&lt;A&gt; v,它还必须提供Allocator&lt;A&gt;()。分配器需要struct A 的成员,如构造函数、复制构造函数、析构函数等。 这里还需要注意的一件重要事情是pointer arithmetic for incomplete type is not allowed.

如果您看到 CLANG 抛出的错误,它显然是一样的。

In file included from /tmp/gcc-explorer-compiler115920-68-1xsb8x7/example.cpp:2:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/vector:64:
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/bits/stl_vector.h:161:9: error: arithmetic on a pointer to an incomplete type 'A'
- this->_M_impl._M_start); }
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/bits/stl_vector.h:253:7: note: in instantiation of member function 'std::_Vector_base<A, std::allocator<A> >::~_Vector_base' requested here
vector()
^

其他一切都很简单。

以下是 typedef ,因此编译器确实需要知道大小。

using abc_vector = std::vector<abc>;

所以,讨论的代码结构很好。

【讨论】:

猜你喜欢
  • 2015-09-11
  • 1970-01-01
  • 2010-09-07
  • 1970-01-01
  • 1970-01-01
  • 2011-05-08
  • 2014-06-21
  • 2017-04-05
  • 1970-01-01
相关资源
最近更新 更多