【问题标题】:std::vector of std::array of different sizes不同大小的 std::array 的 std::vector
【发布时间】:2021-10-19 16:31:03
【问题描述】:

作为一个练习,我想构建一个包含std::array<unsigned char, N> 对象的向量(其中N 不同)。

我的尝试是构造一个基类GenericArray,从中派生出MyArray<N>,这样容器实际上就是:std::vector<GenericArray*>。但是,由于实际的数组变量必须驻留在派生类中,因此我看不到使用来自std:vector<GenericArray*> 本身的这些数据的方法。

这是我的全部尝试,显然会产生:error: ‘class GenericArray’ has no member named ‘data’

#include <array>
#include <cassert>
#include <iostream>
#include <vector>

template<std::size_t N>
using arr_t = std::array<unsigned char, N>;

class GenericArray
{
public:
    ~GenericArray() = default;
};

template<std::size_t N>
class MyArray : public GenericArray
{
public:
    arr_t<N> data;

    MyArray(const arr_t<N>& data)
    {
        this->data = data;
    }
};

int main(void)
{
    std::vector<GenericArray*> vs;

    vs.emplace_back(new MyArray<2>({ 'a', 'b' }));
    vs.emplace_back(new MyArray<4>({ 'A', 'B', 'C', 'D' }));

    assert(vs.size() == 2);

    for (const auto& x : vs[0]->data)
    {
        std::cout << x << "\n";
    }

    return 0;
}

【问题讨论】:

  • 你考虑过std::vector&lt;std::vector&lt;unsigned char&gt;&gt;吗?
  • 我知道存在“更明智”的替代方案,但这只是一个练习(我编辑了帖子)。当这可能是一个实际的限制时,我想了解最好的方法。
  • std::vector&lt;std::vector&lt;unsigned char&gt;&gt; 是完成此任务的最简单解决方案。你也可以使用std::vector&lt;std::unique_ptr&lt;unsigned char[]&gt;&gt;
  • 代码还是有缺陷的。 GenericArray 析构函数不是 virtual。其次,您在代码中引入了new,并且没有对应的delete,因此内存泄漏加上代码更难维护。
  • 您似乎混淆了两个概念。如果你想要容器中的基类指针,this 可以工作。

标签: c++ containers


【解决方案1】:

您似乎混淆了两个概念。我推荐 eerorika 答案中的版本,但如果你真的想要容器中的基类指针,这是一种方法:

#include <array>
#include <iostream>
#include <vector>
#include <memory>

class GenericArray {
public:
    using value_type = unsigned char;
    using iterator = value_type*;

    template<std::size_t N>
    using arr_t = std::array<value_type, N>;

    virtual ~GenericArray() = default; // must be virtual to call the derived dtor
    virtual iterator begin() = 0;      // used for iterating in the derived class
    virtual iterator end() = 0;
    // add `const` versions too as needed
};

template<std::size_t N>
class MyArray : public GenericArray {
public:
    arr_t<N> data;

    MyArray(const arr_t<N>& data) : data(data) {}
    iterator begin() override { return data.data(); }             // overridden
    iterator end() override { return data.data() + data.size(); } // -"-
};

int main() {    // no need for main(void)
    std::vector<std::unique_ptr<GenericArray>> vs;

    vs.emplace_back(new MyArray<2>({ 'a', 'b' }));
    vs.emplace_back(new MyArray<4>({ 'A', 'B', 'C', 'D' }));

    // loop over the elements:
    for(auto& ptr : vs) {
        for(auto& x : *ptr) std::cout << x << ' ';
        std::cout << '\n';
    }
}```

【讨论】:

  • 感谢您为此提供解决方案,并感谢其他人指出最佳实践。我知道std::vector&lt;std::vector&lt;unsigned char&gt;&gt; 是这里最好的选择,但我真的很想满足我的好奇心,你是否可以用这种方式包装std::arrays。
  • @AlexandruDinu 好奇学习总是好的!很高兴它有帮助!
【解决方案2】:

我想构造一个包含 std::array 个对象(其中 N 变化)的向量。

你不能。像所有标准容器一样,向量是同质的。它们由单一元素类型组成。 std::array&lt;unsigned char, N&gt;std::array&lt;unsigned char, M&gt; 是不同的类型 - 假设 N != M,因此它们不能存储在同质容器中。

您可以改用std::vector&lt;std::vector&lt;unsigned char&gt;&gt;

【讨论】:

  • 对,我假设将实际数据包装在GenericArray * 下可以解决这个问题。
  • @AlexandruDinu 这不是一个好的解决方案。向量的向量是更好的解决方案。
  • 我完全理解这一点——但为了论证,鉴于这种限制,人们将如何解决这个问题?
【解决方案3】:

我认为这是不可能的。假设您使用get 方法创建了一个包含std::array&lt;char,N&gt;s secvence 的类。返回结果的大小应该是多少。编译器必须知道所有用于编译的变量的内存大小,但它不知道auto p=vct.get(i); 的大小 如果 get 返回的指针大于auto p=*vct.get(i); 的大小,则未定义。

你能得到的最接近的是返回 void* 并将其转换为 array&lt;char,N&gt;* 但 N 必须是已知的编译时间

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-24
    • 1970-01-01
    • 2014-08-20
    • 2012-07-09
    • 2016-06-15
    • 1970-01-01
    • 2013-09-27
    • 1970-01-01
    相关资源
    最近更新 更多