Я использую внешнюю библиотеку, которая работает с большими объемами данных. Данные передаются необработанным указателем плюс длина. Библиотека не претендует на владение указателем, но вызывает предоставленную функцию обратного вызова (с теми же двумя аргументами), когда это делается с данными.
Данные подготавливаются удобно с помощью std::vector<T>
, и я бы не хотел отказываться от этого удобства. О копировании данных не может быть и речи. Таким образом, мне нужен способ «захватить» буфер памяти, принадлежащий std::vector<T>
, и (позже) освободить его в обратном вызове.
Мое текущее решение выглядит следующим образом:
std::vector<T> input = prepare_input();
T * data = input.data();
size_t size = input.size();
// move the vector to "raw" storage, to prevent deallocation
alignas(std::vector<T>) char temp[sizeof(std::vector<T>)];
new (temp) std::vector<T>(std::move(input));
// invoke the library
lib::startProcesing(data, size);
и в функции обратного вызова:
void callback(T * data, size_t size) {
std::allocator<T>().deallocate(data, size);
}
Это решение работает, потому что функция deallocate
стандартного распределителя игнорирует свой второй аргумент (количество элементов) и просто вызывает ::operator delete(data)
. В противном случае могли бы произойти плохие вещи, так как size
входного вектора может быть немного меньше, чем его capacity
.
Мой вопрос: существует ли надежный (по стандарту С++) способ захвата буфера std::vector
и освобождения его "вручную" через какое-то время?
vector
была функцияdetach
... но это не так - person M.M   schedule 27.11.2014unique_ptr<vector<T>> temp(new vector<T>(move(input)));
? Кроме того, ваше решение работает только в том случае, еслиT
является тривиально разрушаемым типом, иначе вам нужно будет вызыватьallocator<T>::destroy
для каждого элемента. Чтобы ответить на ваш вопрос, нет простого способа получить память отvector
, возможно, вы сможете что-то сделать, используя собственный распределитель, но я бы просто придерживался текущего решения. - person Praetorian   schedule 27.11.2014vector
вы могли бы создать свой собственный векторный класс, который имеет функциюdetach
. - person M.M   schedule 27.11.2014void (*callback)(T * data, size_t size, void * user_data)
иstartProcessing(T* data, size_t size, void * userdata)
, у вас был бы простой путь к решению. - person Michael Anderson   schedule 27.11.2014temp
выйти за рамки? Даже если это сработает на практике, наверняка это неопределенное поведение? (Я спрашиваю, я не знаю ответа) - person Praetorian   schedule 27.11.2014temp
выходит за рамки неопределенного поведения (вместо того, чтобы просто не вызывался деструктор того, что было там помещено)? В документацииstd::allocator<T>::deallocate
указано, что вторым аргументом должен быть именно тот, который был передан вallocate
-- безусловно, нарушение спецификации является нестандартным. - person Grzegorz Herman   schedule 27.11.2014list
- person M.M   schedule 27.11.2014vector
в каком-то (синхронизированном) контейнере, к которому можно получить доступ из обоих мест. Тогда нет необходимости в том, что вы делаете выше. И независимо от того, является ли выходtemp
за рамки UB, вы уже нарушаете контрактallocator::deallocate
, передавая емуsize
, который не обязательно совпадает с переданнымallocator::allocate
. - person Praetorian   schedule 27.11.2014unique_ptr<T[]>
вместоvector<T>
? - person Billy ONeal   schedule 27.11.2014vector
не выходит за рамки. Что-то, что вы должны контролировать потоком кода. Вы можете сделатьlib::startProcesing(input.data(), input.size);
до тех пор, пока эта функция обещает не перераспределять или делать странные вещи со своим указателем. Кто звонитcallback
Кстати? - person alfC   schedule 27.11.2014