【问题标题】:How to constraint several C++ vectors to the same size?如何将多个 C++ 向量限制为相同的大小?
【发布时间】:2012-01-04 13:04:11
【问题描述】:

我有一个包含一组大小相同的 C 动态数组的类,其中一个成员是这些数组的大小:

class stuff {
  int size;
  float *abc;
  float *def;
  // etc.
 };

为了简化此类(以及许多其他具有类似布局的类)的内存管理,我想使用标准容器。但是我必须保持 C 数组(和向量)提供的对齐约束,因为这些数据将在很多 C 函数中传递。

我的问题是每个向量都有自己的大小,这是多余的,如果出于某种原因更改其大小而不是其他原因,可能会导致错误。

有没有办法强制数组/向量/任何东西总是相同的大小?

【问题讨论】:

    标签: c++ arrays stl vector


    【解决方案1】:

    在这种情况下,创建自己的类来管理内存(没有业务逻辑,只有内存)可能是有意义的。

    当然,你可以围绕向量来表达这个类:

    #define CHECK_CLASS_INVARIANT() \
      ClassInvariant inv##__LINE__ (*this); (void) inv##__LINE__;
    
    class Foo {
    public:
      size_t size() const { return _a.size(); }
    
      float* getA() { return &_a[0]; }
      float* getB() { return &_b[0]; }
    
      void push(float a, float b) {
        CHECK_CLASS_INVARIANT()
        _a.push_back(a);
        _b.push_back(b);
      }
    
    private:
      struct ClassInvariant {
        ClassInvariant (Foo& f): _f(f) {}
        ~ClassInvariant () { assert(_f._a.size() == _f._b.size()); }
    
        Foo& _f;
      }; // struct ClassInvariant
    
      std::vector<float> _a;
      std::vector<float> _b;
    };
    

    我们确保始终检查类不变量(在变异方法中)以确保它始终适用。

    注意:这里有一个轻微的流程,如果 _b.push_back(b); 抛出,那么 _a 被扩展而 _b 没有被扩展,这可以在 try/catch 块中处理,或者正如 SteveJessop 恰当地评论的那样,通过 (1) 预先在两个向量中保留足够的空间和 (2) 推入它们。

    【讨论】:

    • 到底为什么要将断言转换为 RAII 类型?
    • @Cat Plus Plus:因为他想在退出范围时检查不变量(这是一个后置条件),即使抛出异常,或者有多个 return 语句,或者在某些情况下可能导致程序员忘记检查它的任何其他内容。在_b.push_back 抛出的情况下,断言将被执行并失败,正确地表明所编写的函数甚至不是弱异常安全的。如果他只是在函数末尾写了assert,那么在这种情况下不会触发。
    • 哦,我想说,在push_back 的情况下,最简单的修复方法可能是在推送它们之前对reserve 两个向量,而不是尝试捕获异常并撤消第一次推动。但这只是因为push_back 是一个函数的特例,它可以在适当的前提条件(足够的容量)下抛出。
    • 更重要的是,你到底为什么要在那个宏中加上分号? ;-)
    • @SteveJessop:特殊的编码习惯,我不明白为什么在我已经写好宏名称之后还要记住要放一个分号。显然,我宁愿不使用宏,但是太多编译器在使用“守卫”变量时滥用“未使用的变量”......
    【解决方案2】:

    没有通用和明确的方法来约束向量。约束必须作为算法的不变量强制执行;每当您将push_back 数据发送到一个向量时,也将其推送到另一个向量。 (请务必保留矢量private

    【讨论】:

      【解决方案3】:

      改为保留一对浮点数的向量怎么样?

      【讨论】:

      • 这更有意义,但我需要能够将数据传递给 C 风格的函数接受指针,例如make_something(&amp; st.abc[0])。更改这些数组的布局需要更新这些 C 函数,这实际上是不可行的。
      【解决方案4】:

      我不是 100% 确定我理解你的问题是什么,但看起来你想要这样的东西:

      template<int SIZE> class stuff {
        float abc[SIZE];
        float def[SIZE];
        // etc.
       };
      

      这没有内存管理问题——您可以在堆栈或堆上创建一个“stuff”类,它不需要析构函数。

      【讨论】:

      • 模板不起作用,因为元素的数量只有在运行时才知道。
      • @JoshGreifer:动态数组通常意味着一个数组,其大小在运行时可能会发生变化。此外,SIZE 不必为负数,因此无符号整数(无论您喜欢哪个)在这里会更好。
      • Ok kbok,仍然不确定我是否理解:它们是“动态的”,(即构造后元素的数量可能会有所不同),但它们被限制为具有相同的大小,或者它们是否有效构造在运行时具有固定大小(在编译时大小未知),并在其整个生命周期内保持其大小?在后一种情况下,它只是数组由“stuff”类拥有(管理)的一种情况,而不是将其用作引用数组集合的便利类。
      • 是的 matthieu 我同意——我选择 int 是有意的——在提供代码以回答问题时,我尝试使代码 sn-ps 尽可能接近 O.P 的代码—— - 我总是在自己的代码中使用 size_types!
      • @JoshGreifer :元素的数量会随时间变化(这就是我首先使用向量的原因)。
      猜你喜欢
      • 1970-01-01
      • 2019-12-19
      • 2021-09-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-13
      相关资源
      最近更新 更多