How to move a std::vector into a raw array in C++
Asked Answered
C

2

8

How can I move the contents of std::vector into an array safely without copying or iterating over all elements?

void someFunc(float* arr, std::size_t& size)
{
   std::vector<float> vec(5, 1.5f);
   // do something with the data

   size = vec.size();
   arr = vec.data(); // this doesn't work, as at the end of the function the data in std::vector will be deallocated

}

main()
{
   float* arr;
   std::size_t size{0};

   someFunc(arr, size);

   // do something with the data
   delete [] arr;
}

How can I assign my array with the data in std::vector and making sure that deallocation will not be called on std::vector? Or maybe any other ideas to go around this?

Chesty answered 2/10, 2019 at 15:33 Comment(11)
What is your goal? Why not keep the vector and use its .data()?Hardboiled
You can use a vector<T> on legacy functions that take a T*. As stated, just use the data() member. There is no need to shuffle between vector and a regular array, if this is what you were intending to do.Rhigolene
Well, I actually can stick with std::vector, but still need to use some old code that consider the data to be in raw array. And I really don't want to edit or rewrite the old codeChesty
@BoboFeugo -- But all you need is to pass data() to the top-level "old code" function, and the rest is all an array, the old code has no idea the data was being managed by a vector. Have you ever used data()?Rhigolene
@Rhigolene That only works if the "old code" doesn't want to assume ownership.Cyclostyle
As I know data() will return a pointer to const data, but I need to modify the dataChesty
@BoboFeugo only from a const vector. From a mutable vector you get a pointer-to-mutableHerwin
@MaxLanghof The only thing I can think of that the old code would have done with ownership that would totally mess this up is to call delete[] on the pointer (which is a bad design to being with).Rhigolene
@Rhigolene or free(), or delete, or lib_MyBadOlLib_Free()Herwin
@BoboFeugo You are thinking of std::string::c_str(), where the return value is const. Not so for a non-const vector.Rhigolene
I want to do exactly this because I am using a library (lodepng) that reads a file into a vector. I want to return a unique_ptr that wraps the vector's data, which could be very large (or I want to repeat the operation many times; either way I don't want to allocate, read, then copy, nor do I want to return the vector itself, though this is likely what I'll settle on).Vanhook
T
7

You can't.

A vector owns its buffer. You cannot steal it.

You will have to copy/move the elements individually, optionally using a helper algorithm that does the iteration for you (std::copy/std::move).

(Also note that, since your element type is just float, a move here is a copy.)

(Also note that this std::move, the algorithm, is not the same as std::move, the rvalue cast.)


Consider whether you really need to do this. You can treat the vector's data as an array using vec.data() whenever you need to, as long as you keep the vector alive. Surely that's better than sacrificing RAII?

Tergum answered 2/10, 2019 at 15:35 Comment(5)
So how do you use std::move for this purpose?Chesty
en.cppreference.com/w/cpp/algorithm/move Though, since you only have floats, "move" will really just be a copy.Tergum
actually the move I asked for is not the one from the standard algorithm, instead i wanted something like move-semantics or a shallow copy. But as the most comments stated that it's not possible, i may have to change my implementation!Chesty
@Bobo Indeed, you're asking how to move (or "steal") the vector's internal buffer - you can't do that. Well, you can steal it into another vector, but that doesn't help you ;) The std::move I'm talking about is for the "individual" elements.Tergum
@LightnessRacesinOrbit why not the other way around, where you have the vector steal from a pre-existing allocation? This answer is pretty defeatistSovereign
M
0

This would have been handy for me for stealing a "typed" vector contents into an "untyped" vector.

This is what I want to do:

std::vector<uint8_t>­one;
std::vector<V> other = std::move(one);

When I know that the contents are exactly what I expect (there is a runtime type info field)

I would use this to do 'move semantics' between an untyped and a typed class where part of the underlying representation is in a vector - just in the typed case it is vector of Vs.

Think of it as a different "view" of the data. In general cases the data is untyped as there are special edge-cases, but after handling them via branching it would be handy to handle the "normal" cases type safe ways..

I see I can implement this behaviour if I throw out std::vector and do my implementation using direct pointer arithmetic as then I can access that in move construction, but I would love to not give up on vectors...

Just wanted to add this to show what kind of rationale might be behind these kind of questions and I think sometimes it is valid

Methodism answered 29/6, 2020 at 11:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.