Using std::vector as view on to raw memory

后端 未结 10 1607
感动是毒
感动是毒 2021-01-31 13:34

I\'m using a external library which at some point gives me a raw pointer to an array of integers and a size.

Now I\'d like to use std::vector to access and

相关标签:
10条回答
  • 2021-01-31 13:54

    You could use a std::reference_wrapper available since C++11:

    #include <iostream>
    #include <iterator>
    #include <vector>
    #include <algorithm>
    
    int main()
    {
        int src_table[] = {5, 4, 3, 2, 1, 0};
    
        std::vector< std::reference_wrapper< int > > dest_vector;
    
        std::copy(std::begin(src_table), std::end(src_table), std::back_inserter(dest_vector));
        // if you don't have the array defined just a pointer and size then:
        // std::copy(src_table_ptr, src_table_ptr + size, std::back_inserter(dest_vector));
    
        std::sort(std::begin(dest_vector), std::end(dest_vector));
    
        std::for_each(std::begin(src_table), std::end(src_table), [](int x) { std::cout << x << '\n'; });
        std::for_each(std::begin(dest_vector), std::end(dest_vector), [](int x) { std::cout << x << '\n'; });
    }
    
    0 讨论(0)
  • 2021-01-31 13:55

    C++20's std::span

    If you are able to use C++20, you could use std::span which is a pointer - length pair that gives the user a view into a contiguous sequence of elements. It is some sort of a std::string_view, and while both std::span and std::string_view are non-owning views, std::string_view is a read-only view.

    From the docs:

    The class template span describes an object that can refer to a contiguous sequence of objects with the first element of the sequence at position zero. A span can either have a static extent, in which case the number of elements in the sequence is known and encoded in the type, or a dynamic extent.

    So the following would work:

    #include <span>
    #include <iostream>
    #include <algorithm>
    
    int main() {
        int data[] = { 5, 3, 2, 1, 4 };
        std::span<int> s{data, 5};
    
        std::sort(s.begin(), s.end());
    
        for (auto const i : s) {
            std::cout << i << "\n";
        }
    
        return 0;
    }
    

    Check it out live

    Since std::span is basically pointer - length pair, you can use in a following manner too:

    size_t size = 0;
    int *data = get_data_from_library(size);
    std::span<int> s{data, size};
    

    Note: Not all compilers support std::span. Check compiler support here.

    UPDATE

    If you are not able to use C++20, you could use gsl::span which is basically the base version of the C++ standard's std::span.

    C++11 solution

    If you are limited to C++11 standard, you can try implementing your own simple span class:

    template<typename T>
    class span {
       T* ptr_;
       std::size_t len_;
    
    public:
        span(T* ptr, std::size_t len) noexcept
            : ptr_{ptr}, len_{len}
        {}
    
        T& operator[](int i) noexcept {
            return *ptr_[i];
        }
    
        T const& operator[](int i) const noexcept {
            return *ptr_[i];
        }
    
        std::size_t size() const noexcept {
            return len_;
        }
    
        T* begin() noexcept {
            return ptr_;
        }
    
        T* end() noexcept {
            return ptr_ + len_;
        }
    };
    

    Check out C++11 version live

    0 讨论(0)
  • 2021-01-31 13:55

    Since the algorithm-library works with iterators you can keep the array.

    For pointers and known array length

    Here you can use raw pointers as iterators. They support all the opertations an iterator supports (increment, comparison for equality, value of, etc...):

    #include <iostream>
    #include <algorithm>
    
    int *get_data_from_library(int &size) {
        static int data[] = {5,3,2,1,4}; 
    
        size = 5;
    
        return data;
    }
    
    
    int main()
    {
        int size;
        int *data = get_data_from_library(size);
    
        std::sort(data, data + size);
    
        for (int i = 0; i < size; i++)
        {
            std::cout << data[i] << "\n";
        }
    }
    

    data points to the dirst array member like an iterator returned by begin() and data + size points to the element after the last element of the array like an iterator returned by end().

    For arrays

    Here you can use std::begin() and std::end()

    #include <iostream>
    #include <algorithm>
    
    int main()
    {
        int data[] = {5,3,2,1,4};         // raw data from library
    
        std::sort(std::begin(data), std::end(data));    // sort raw data in place
    
        for (int i = 0; i < 5; i++)
        {
            std::cout << data[i] << "\n";   // display sorted raw data 
        }
    }
    

    But keep in mind that this only works, if data does not decay to a pointer, because then length information goes missing.

    0 讨论(0)
  • 2021-01-31 14:03

    You can't do this with a std::vector without making a copy. std::vector owns the pointer it has under the hood and allocates space through the allocator that is provided.

    If you have acess to a compiler that has support for C++20 you could use std::span which was built for exactly this purpose. It wraps a pointer and size into a "container" that has the C++ container interface.

    If not, you can use gsl::span which is what the standard version was based off of.

    If you don't want to import another library you could trivially implement this yourself depending on what all functionality you want to have.

    0 讨论(0)
提交回复
热议问题