【问题标题】:How to cheaply assign C-style array to std::vector?如何廉价地将 C 样式数组分配给 std::vector?
【发布时间】:2011-08-15 17:34:20
【问题描述】:

目前我执行以下操作:

// float *c_array = new float[1024];

void Foo::foo(float *c_array, size_t c_array_size) {
  //std::vector<float> cpp_array;

  cpp_array.assign(c_array, c_array + c_array_size);
  delete [] c_array;
}

如何优化此分配?我不想执行元素复制,而只是交换指针。

【问题讨论】:

  • 没有。但是 C++0x 方法也很好看。
  • 这实际上不是一个重复的问题。链接的问题仅涉及从向量到数组,而不是从数组到向量。
  • @ariddell 确实如此。链接的问题已被编辑以包含此内容,但那是在最初询问之后将近一年,并且没有一个答案实际上解决了问题的这一部分。
  • 2018 年有什么更新吗?

标签: c++ arrays stl vector stdvector


【解决方案1】:

当前的std::vector 不提供任何功能或接口来获取先前分配的存储的所有权。想必意外传入堆栈地址太容易了,导致问题多于解决的问题。

如果您想避免复制到向量中,则需要在整个调用链中使用向量,或者始终使用 C 方式使用 float[]。你不能混合它们。您可以保证&amp;vec[0] 将等同于 C 数组,但完全连续,因此在整个程序中使用向量可能是可行的。

【讨论】:

  • 现在还是这样吗?
  • @Jay 是的。
【解决方案2】:

目前,std::vector 接口不具备移动或交换除另一个 std::vector 之外的任何东西的能力。

【讨论】:

  • 而且未来不太可能。大多数你想要这个的用例,你可以使用原始数组,而添加到 std::vector 的额外簿记将是可怕的。
  • 认为至少在 C++0x 中有一个提议允许这种情况发生。但是,我并不完全确定。
  • @Mark:实际上,如果向量拥有内存的所有权,它就不需要额外的簿记。但是有很多方法可能会错误地使用此类功能,我相信您对可能性的评估是准确的。
【解决方案3】:

唯一的方法是创建一个自定义分配器。

  1. 编写一个可以用数组初始化的分配器类。

  2. 使用分配器作为参数来实例化向量。

【讨论】:

  • 这并不像你想象的那么有用,因为向量会覆盖任何预先存在的数据。
  • @geotavros -- 我得翻出一本手册。我已经很久没有编写自定义分配器了。我不确定我是否可以解决丹尼斯指出的问题。可能不会,但我会尽快找时间看看。
【解决方案4】:

不太可能——这很危险,因为 std::vector 不知道内存是如何分配的以及应该如何释放它。

如果可能,您可以用创建正确大小的 std::vector 来替换原始分配。它使用连续的内存区域,因此可以替换手动分配的缓冲区。

【讨论】:

    【解决方案5】:

    可以使用自定义分配器。我用 clang 和 gcc 检查了 godbolt.org。对我来说,它看起来有点丑陋 - 但它至少可以作为概念证明。

    当然,你必须自己照顾数组的生命周期。

    #include <vector>
    #include <iostream>
    
    // custom allocator
    template <typename T>
    class my_allocator {
      private:
        T* const addr;
      public:
        template <typename U>
        struct rebind {
          typedef my_allocator<U> other;
        };
    
        //provide the required no-throw constructors / destructors:
        constexpr my_allocator(T* addr_) : addr(addr_) { };
        constexpr my_allocator(const my_allocator<T>& rhs) : addr(rhs.addr) { };
        template <typename U>
        my_allocator(const my_allocator<U>& rhs, T* addr_) : addr(addr_) { };
        ~my_allocator()  { };
    
        //import the required typedefs:
        using value_type=T;
        using pointer=T*;
        using reference=T&;
        using const_pointer=const T*;
        using const_reference=const T&;
        using size_type=size_t;
        using difference_type=ptrdiff_t;
    
      constexpr pointer   allocate(size_type n, const void * = 0) {
                  pointer t=addr;
                  std::cout
                  << "  used my_allocator to allocate   at address "
                  << t << " (+)" << std::endl;
                  return addr;
                }
    
        constexpr void      deallocate(void* p, size_type) {
            if (p) {
            std::cout
            << "  used my_allocator to deallocate at address "
            << p << " (-)" << 
            std::endl;
            } 
        }
    
        template< class U, class... Args >
        void construct( U* p, Args&&... args ) {
            // avoids initialisation of the elements.
            std::cout << "Contruct called" << std::endl;
        }
    
    };
    
    // helper function for easy useage
    template<typename T>
    const std::vector<T, my_allocator<T> > CreateVectorFromArray(T* array, int size) {
        const my_allocator<T> alloc=my_allocator<T>(array);
        std::vector<int, my_allocator<int> > vecAll(size, my_allocator<int>(array));
        return vecAll;
    }
    
    template<typename T>
    using element_type_t = std::remove_reference_t<decltype(*std::begin(std::declval<T&>()))>;
    
    template<typename AR>
    auto CreateVectorFromArrayAr(AR& array) {
        using T=element_type_t<AR>;
        const my_allocator<T> alloc=my_allocator<T>(array);
        std::vector<T, my_allocator<T> > vecAll(sizeof(array)/sizeof(array[0]), my_allocator<T>(array));
        return vecAll;
    }
    
    int main() {
        int array[]={0,1,2,3,4,5,6,7,8,9};
        std::cout << "Array:  " << &array[0] << " " << array[0]  << " " << array[1]<< " " << array[2] << std::endl;
    
        auto vecAll=CreateVectorFromArray(array, sizeof(array)/sizeof(array[0]));
        auto vec3=CreateVectorFromArrayAr(array);
    
    
        std::cout << "Vector: " << &vecAll[0] << " " << vecAll[0] << " " << vecAll[1]<< " " << vecAll[2] << std::endl;
        std::cout << "Array:  " << &array[0] << " " << array[0]  << " " << array[1] << " " << array[2] << std::endl;
        std::cout << "vec3:   " << &vec3[0] << " " << vec3[0]  << " " << vec3[1] << " " << vec3[2] << std::endl;
        std::cout << "sizeof(vecAll)=" << sizeof(vecAll) << std::endl;
        std::cout << "sizeof(void*)=" << sizeof(void*) << std::endl;
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 2017-04-07
      • 1970-01-01
      • 2011-01-26
      • 2020-08-20
      • 2018-07-02
      • 2019-11-07
      • 1970-01-01
      • 1970-01-01
      • 2020-10-11
      相关资源
      最近更新 更多