【问题标题】:How do you get a std::list to allocate memory for n amount of objects in C++?你如何获得一个 std::list 来为 C++ 中的 n 个对象分配内存?
【发布时间】:2020-12-22 23:57:28
【问题描述】:

我的目标是有一个 std::list 为我将放入其中的对象分配足够的内存,因此我不必在它扩展时处理潜在的异常,或者它扩展所需的额外时间。

我的第一次尝试是从波表拼接:

std::list<T> list();
        auto listI = list.begin;
        typename std::list<T>::iterator waveStart = waveTable.begin();
        for(int i = 0; i < waveIndex; i++) {
            waveStart++;
        }
        typename std::list<T>::iterator waveEnd;
        int tCounter = nSamples;
        while(tCounter > 0) {
            if(tCounter > (waveTable.size() - waveIndex)) {
                waveEnd = waveStart;
                for(int i = 0; i < (waveTable.size() - waveIndex); i++) {
                    waveEnd++;
                }
                tCounter = (tCounter - (waveTable.size() - waveIndex));
            } else {
                waveEnd = waveStart;
                for(int i = 0; i < tCounter; i++) {
                    waveEnd++;
                }
                tCounter = 0;
            }
            list.splice(listI, waveTable, waveStart, waveEnd);
            waveStart = waveTable.begin();
        }

        phase += (tp * frequency * (nSamples/sampleRate));
        while(phase > tp) {
            phase -= tp;
        }
        waveIndex = (phase / tp) * waveTable.size();

我本来打算复制这些值,但是 splice 从 waveTable 中删除了这些值,所以我打算使用 insert。

问题是,插入会增加列表的大小,我无法找到一种方法来告诉列表需要多少内存来保存我想要存储的所有值。

【问题讨论】:

    标签: c++ list std


    【解决方案1】:

    我的目标是有一个 std::list 为我将放入其中的对象分配足够的内存

    好的,看起来有道理。您可以通过调用@Gyross 提到的适当构造函数来做到这一点。

    所以当它扩展时我不必处理潜在的异常

    现在这就是您的问题不再有意义的地方。如果您内存不足,那么预分配肯定不会解决问题。此外,根据您的类型,当您调用复制(或在某些情况下)移动分配函数时(使用 node = newvalue 时),它仍然可能引发异常。

    或扩展所需的额外时间

    具有讽刺意味的是,您使用 std::list 并如此关心性能,因为它是标准库中最慢的容器之一。如果您想要一个高性能的固定容器,我建议您编写/使用环形缓冲区。

    【讨论】:

      【解决方案2】:

      您可以在构造函数中指定初始大小,使用std::list&lt;T&gt; list_obj(n)

      https://en.cppreference.com/w/cpp/container/list/list

      还有std::list::resize

      【讨论】:

      • 但是插入会增加大小
      • insert 总是会增加大小,而不是做list.insert(it, val),做*it = val
      【解决方案3】:

      您可能希望了解实现自定义分配器。

      自定义分配器类的完整要求在这里 https://en.cppreference.com/w/cpp/memory/allocator

      以下示例分配器始终在堆栈上分配num_items 元素,如果元素数量超过静态定义的大小,则抛出std::bad_alloc()

      如果您有很多元素,您可能希望使用 new delete 或类似方法从堆栈中移开以避免溢出。

      template<typename T, size_t num_items>
      class MyAllocator
      {
      public:
          using value_type = T;
          using pointer = T*;
          using const_pointer = const T*;
          using void_pointer = std::nullptr_t;
          using const_void_pointer = const std::nullptr_t;
          using reference = T&;
          using const_reference = const T&;
          using size_type = std::size_t;
          using difference_type = std::ptrdiff_t;
      
          /* should copy assign the allocator when copy assigning container */
          using propagate_on_container_copy_assignment = std::true_type;
      
          /* should move assign the allocator when move assigning container */
          using propagate_on_container_move_assignment = std::true_type;
      
          /* should swap the allocator when swapping the container */
          using propagate_on_container_swap = std::true_type;
      
          /* two allocators does not always compare equal */
          using is_always_equal = std::false_type;
      
          MyAllocator() : m_index(0) {};
          ~MyAllocator() noexcept = default;
      
          template<typename U>
          struct rebind {
              using other = MyAllocator<U, num_items>;
          };
      
          [[nodiscard]] pointer allocate(size_type n) {
              if (m_index+n >= num_items)
                  throw std::bad_alloc();
      
              pointer ret = &m_buffer[m_index];
              m_index += n;
              return ret;
      
          }
      
          void deallocate(pointer p, size_type n) {
              (void) p;
              (void) n;
              /* do nothing */
          }
      
          size_type max_size() {
              return num_items;
          }
      
      
          bool operator==(const MyAllocator& other) noexcept {
              /* storage allocated by one allocator cannot be freed by another */
              return false;
          }
      
          bool operator!=(const MyAllocator& other) noexcept {
              /* storage allocated by one allocator cannot be freed by another */
              return !(*this == other);
          }
      
      private:
          value_type m_buffer[num_items];
          size_t m_index;
      };
      
      

      然后你就可以使用了

      constexpr size_t always_allocate_this_amount_of_elements = 10;
      std::list<int, MyAllocator<int, always_allocate_this_amount_of_elements>> list;
      

      【讨论】:

      • 我不认为你可以像这样直接将值存储在分配器中,我认为状态需要在外部池中......
      • 我认为如果 == 运算符并不总是比较相等,则支持有状态分配器。但我还是建议远离堆栈
      猜你喜欢
      • 2020-06-12
      • 2011-03-19
      • 1970-01-01
      • 1970-01-01
      • 2011-02-18
      • 1970-01-01
      • 2018-12-16
      • 2010-11-09
      • 1970-01-01
      相关资源
      最近更新 更多