Reputation: 5487
Currently I do the following:
// 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;
}
How can I optimize this assigning? I would like not to perform elementwise copy but just swap pointers.
Upvotes: 31
Views: 15678
Reputation: 181
It is possible with the use of a custom allocator. I checked on godbolt.org with clang and gcc. To me, it looks a bit of an ugly hack – but it works at least as a proof of concept.
Of course, you have to take care of the lifetime of the array for yourself.
#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;
}
Upvotes: 0
Reputation: 7939
The only way to do it would be to create a custom allocator.
Write an allocator class that you can initialise with your array.
Instantiate the vector with the allocator as an argument.
Upvotes: 5
Reputation: 96291
The current std::vector
doesn't provide any capability or interface to take ownership of previously allocated storage. Presumably it would be too easy to pass a stack address in by accident, allowing more problems than it solved.
If you want to avoid copying into a vector, you'll either need to use vectors through your entire call chain, or do it the C way with float[]
the entire time. You can't mix them. You can guaranteed that &vec[0]
will be equivalent to the C-array though, fully contiguous, so using vector in the whole program may be feasible.
Upvotes: 26
Reputation: 6375
Unlikely it's possible - it's quite dangerous, because std::vector doesn't know how the memory was allocated and how it should be freed.
If it's possible, you may replace original allocation with creation of std::vector of correct size. It uses contiguous memory area, so it can replace manually allocated buffer.
Upvotes: 1
Reputation: 146988
Currently, the std::vector
interface does not possess the capacity to move from or swap with anything except another std::vector
.
Upvotes: 6