Initialize std::vector with given array without std::allocator

Viewed 143

I am using an external library which provides a function with the following interface:

void foo(const std::vector<int>& data);

I am receiving a very large C-style array from another library which has already been allocated:

int* data = bar();

Is there any way for me to pass on data to foo without allocating and copying each element? data is very large and therefore I want to avoid a copy and allocation if possible.

I could have used allocators, but foo is not templated for an allocator, so I don't believe this is possible.

I understand I may be asking for magic, but if it is possible that would be great. Of course if foo rather took an std::span this would not be a problem.

2 Answers

Magic

This answer is magic, dependent on the implementation of the compiler.

We can forcibly access the container of a vector.

Take g++ as an example. It uses three protected pointers, _M_start, _M_finish, and _M_end_of_storage to handle storage. So we can create a derived class that sets/resets the pointers to the return of vaule bar() in the constructor and destructor.

Example code for g++:

static_assert(__GNUC__ == 7 && __GNUC_MINOR__ == 5 && __GNUC_PATCHLEVEL__ == 0);

class Dmy: public std::vector<int>
{
    public:
        Dmy(int *b, int *e)
        {
            _M_impl._M_start = b;
            _M_impl._M_finish = e;
            _M_impl._M_end_of_storage = _M_impl._M_finish;
        }

        ~Dmy()
        {
            _M_impl._M_start = 0;
            _M_impl._M_finish = 0;
            _M_impl._M_end_of_storage = 0;
        }
};

foo(Dmy(data, end_of_data));

Is there any way for me to pass on data to foo without allocating and copying each element?

No, there's no way of avoiding it given the premise.

There are two alternative workarounds by changing the premise:

  • Change the other library to return a vector.
  • Change foo to not require a vector. As you point out, std::span would probably be a reasonable choice.
Related