Нет законного способа сделать это в C ++; Вы можете перемещать буферы только с std::vector
на другой std::vector
того же типа.
Существует множество способов взломать это. Самым нелегальным и злым будет
std::vector<uint32_t> evil_steal_memory( std::vector<int32_t>&& in ) {
return reinterpret_cast< std::vector<uint32_t>&& >(in);
}
или что-то подобное.
Менее злой способ - забыть, что это std::vector
.
template<class T>
struct buffer {
template<class A>
buffer( std::vector<T,A> vec ):
m_begin( vec.data() ),
m_end( m_begin + vec.size() )
{
m_state = std::unique_ptr<void, void(*)(void*)>(
new std::vector<T,A>( std::move(vec) ),
[](void* ptr){
delete static_cast<std::vector<T,A>*>(ptr);
}
);
}
buffer(buffer&&)=default;
buffer& operator=(buffer&&)=default;
~buffer() = default;
T* begin() const { return m_begin; }
T* end() const { return m_end; }
std::size_t size() const { return begin()==end(); }
bool empty() const { return size()==0; }
T* data() const { return m_begin; }
T& operator[](std::size_t i) const {
return data()[i];
}
explicit operator bool() const { return (bool)m_state; }
template<class U>
using is_buffer_compatible = std::integral_constant<bool,
sizeof(U)==sizeof(T)
&& alignof(U)==alignof(T)
&& !std::is_pointer<T>{}
>;
template<class U,
std::enable_if_t< is_buffer_compatible<U>{}, bool > = true
>
buffer reinterpret( buffer<U> o ) {
return {std::move(o.m_state), reinterpret_cast<T*>(o.m_begin()),reinterpret_cast<T*>(o.m_end())};
}
private:
buffer(std::unique_ptr<void, void(*)(void*)> state, T* b, T* e):
m_state(std::move(state)),
m_begin(begin),
m_end(end)
{}
std::unique_ptr<void, void(*)(void*)> m_state;
T* m_begin = 0;
T* m_end = 0;
};
живой пример : этот тип стирает буфер T
.
template<class T>
struct raster {
buffer<T> v;
template<typename U, typename = std::enable_if_t<sizeof(T) == sizeof(U)>>
raster(raster<U>&& other):
v( buffer<T>::reinterpret( std::move(other).v ) )
{}
};
обратите внимание, что у моего buffer
есть выделенная память; по сравнению с миллионами элементов это дешево. Это также только для перемещения.
Выделение памяти может быть устранено путем осторожного использования оптимизации небольшого буфера.
Я бы оставил это только для перемещения (кто хочет случайно скопировать миллион элементов?) И, возможно, напишу
buffer clone() const;
, который создает новый буфер с тем же содержимым.
Обратите внимание, что вместо const buffer<int>
вы должны использовать buffer<const int>
в соответствии с вышеуказанным дизайном. Вы можете изменить это, дублируя методы begin() const
, чтобы иметь постоянную и неконстантную версии.
Это решение основано на вашей уверенности, что реинтерпретация буфера int32_t
s как буфера uint32_t
s (или наоборот) ни с чем не повлияет. Ваш компилятор может предоставить эту гарантию, но стандарт C ++ не .