【问题标题】:How can I declare a member vector of the same class?如何声明同一类的成员向量?
【发布时间】:2017-06-14 07:00:56
【问题描述】:

为什么下面的代码可以工作?

struct A {
    std::vector<A> subAs;
};

A 是不完全类型,对吧?如果有一个 A*s 的向量,我会理解的。但在这里我不明白它是如何工作的。这似乎是一个递归定义。

【问题讨论】:

  • 好吧,在最底层,这是否是“递归定义”取决于std::vector 类本身是否包含A 类型的任何子对象。在std::vector 的典型实现中,没有A 类型的直接子对象。在std::vector 的典型实现中,它将仅包含一个指向受控序列的A * 指针。这消除了数据递归并使使用不完整类型作为参数成为可能。这里唯一的问题是语言规范是允许还是要求它。

标签: c++ templates vector member incomplete-type


【解决方案1】:

这个paperinto C++17 采用,它允许在某些STL 容器中使用不完整的类型。在此之前,它是未定义的行为。引用论文:

基于 Issaquah 会议的讨论,我们实现了 一致同意*继续采用该方法——“不完整的容器 类型”,但将范围限制为 std::vectorstd::liststd::forward_list,作为第一步。

至于标准的变化(强调我的):

在实例化 vector 时可能会使用不完整的类型 T,如果 allocator 满足 allocator-completeness-requirements (17.6.3.5.1)。 T 应在结果的任何成员之前完成 引用了向量的特化。

所以,你有它,如果你在实例化std::vector&lt;T, Allocator&gt; 时保留默认的std::allocator&lt;T&gt;,那么根据论文,它将始终使用不完整的类型T;否则,这取决于您的 Allocator 是否可以使用不完整的类型 T 进行实例化。


A 是不完全类型,对吧?如果有一个 A*s 的向量,我会理解的。但在这里我不明白它是如何工作的。这似乎是一个递归定义。

那里没有递归。在极其简化的形式中,它类似于:

class A{
    A* subAs;
};

从技术上讲,除了sizecapacity 和可能的allocatorstd::vector 只需要保存一个指向它通过其分配器管理的动态数组A 的指针。 (并且指针的大小在编译时是已知的。)

因此,实现可能如下所示:

namespace std{

    template<typename T, typename Allocator = std::allocator<T>>
    class vector{

        ....

        std::size_t m_capacity;
        std::size_t m_size;
        Allocator m_allocator;
        T* m_data;
    };

}

【讨论】:

  • 这是一个有用的答案,但我对 C++17 的引用感到困惑。这种模式在我的 C++14 编译器中当然工作得很好。
  • 在早期版本中,支持似乎取决于实现 - 最新版本的 GCC 和 Clang 即使在 C++11 模式下也接受类型不完整的 std::vector,但 MSVC 不接受。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-10-08
  • 1970-01-01
  • 1970-01-01
  • 2010-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多