Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > Копирование std::vector в void*


Автор: C/L 31.3.2009, 15:56
Как лучше копировать контейнер vector. Есть специальные шаблонные функции, но они не всегда подходят, особенно если копировать в void указатель. Попробывал вот так:
Код

void TPRIMITIVE::Fill(void *dest){
    for(TVERTARR::iterator it = verts.begin(); it < verts.end(); it++){
        *(TVERTEX *)dest = *it;
        (TVERTEX *)(dest)++;
    }
}

пишет: error C2036: void *: неизвестный размер.
Может лучше подойдет memcpy?

Автор: zim22 31.3.2009, 16:05
Цитата(C/L @  31.3.2009,  15:56 Найти цитируемый пост)
Может лучше подойдет memcpy?

попробуйте. может и лучше. ведь особенность вектора в том, что он располагает свои элементы в непрерывном блоке памяти и следовательно к нему можно применять сишные функции для работы с ней.

можно так:
Код

void *p = GetPtr(); // p указывает на какую-то область с данными, подлежащими копированию
vector<unsigned char> vi(10); // вектор байтов.
memcpy(&vi.front(), p, vi.size()); 

Автор: mrbrooks 31.3.2009, 16:07
C/L, попробуй через reinterpret_cast, не знаю правда, что получится  smile 

Автор: C/L 31.3.2009, 16:31
Цитата(zim22 @  31.3.2009,  18:05 Найти цитируемый пост)
можно так:
Код

void *p = GetPtr(); // p указывает на какую-то область с данными, подлежащими копированию
vector<unsigned char> vi(10); // вектор байтов.
memcpy(&vi.front(), p, vi.size());

спасибо, попробую. Значит front() указывает на начало как и begin()?

Автор: InvalidProperty 31.3.2009, 16:32
Цитата(zim22 @ 31.3.2009,  16:05)
Цитата(C/L @  31.3.2009,  15:56 Найти цитируемый пост)
Может лучше подойдет memcpy?

попробуйте. может и лучше. ведь особенность вектора в том, что он располагает свои элементы в непрерывном блоке памяти и следовательно к нему можно применять сишные функции для работы с ней.

можно так:
Код

void *p = GetPtr(); // p указывает на какую-то область с данными, подлежащими копированию
vector<unsigned char> vi(10); // вектор байтов.
memcpy(&vi.front(), p, vi.size()); 

Для memcpy третьим параметром нужно размер в байтах указывать, т.о. получается:
memcpy(&vi.front(), p, vi.size() * sizeof(unsigned char));
в данном случае, конечно, и так прокатывает, но вообще нужно знать.

Автор: bsa 31.3.2009, 16:39
C/L, во-первых, по правилам положено проверять условие it != verts.end(). У всех итераторов есть оператор неравно, а вот оператор меньше - только у RandomAccessIterator.
во-вторых, в общем случае it++ выполняется дольше, чем ++it. Лучше используй префиксную форму, если тебе нет потребности в постфиксной.
в-третьих, можно писать так:
Код
std::copy(verts.begin(), verts.end(), std::back_inserter<TVERTEX>(static_cast<TVERTEX*>(dest)));
Хотя, лично я бы написал так:
Код
std::memcpy(dest, &*verts.begin(), sizeof(TVERTEX)*verts.size());

Автор: azesmcar 31.3.2009, 16:43
Цитата

попробуйте. может и лучше. ведь особенность вектора в том, что он располагает свои элементы в непрерывном блоке памяти и следовательно к нему можно применять сишные функции для работы с ней.

нельзя...нехорошо это

1. если используете memcpy, то используйте обыкновенный буфер. Не мешайте сишние функции с контейнерами, вы нарушаете инкапсуляцию.
2. it < verts.end() - это непереносимый код, используйте it != verts.end()
3. void* тоже штука нехорошая..

что конкретно надо сделать? может найдем другое решение?

Добавлено через 3 минуты и 7 секунд
неверно понял..тут копируем ИЗ контейнера а не В контейнер, тогда инкапсуляция не нарушается, но некрасиво все равно  smile 

Автор: vinter 31.3.2009, 17:15
Цитата(bsa @  31.3.2009,  17:39 Найти цитируемый пост)
C/L, во-первых, по правилам положено проверять условие it != verts.end().

нет таких правил

Цитата(azesmcar @  31.3.2009,  17:43 Найти цитируемый пост)
2. it < verts.end() - это непереносимый код

вполне переносимый

Автор: bsa 31.3.2009, 17:22
Цитата(vinter @ 31.3.2009,  17:15)
Цитата(bsa @  31.3.2009,  17:39 Найти цитируемый пост)
C/L, во-первых, по правилам положено проверять условие it != verts.end().

нет таких правил

Имхо, это правило такое же, как "нельзя использовать goto". Т.е. для новичков. Когда набьет руку, то уже сам сообразит, что и когда использовать.

Автор: azesmcar 31.3.2009, 17:23
vinter оператор < работает только для RandomAccessIterator как и написал bsa. Непереносимый я сказал в том смысле что с другими контейнерами не работает..лучше в данном случает писать != (возможно термин не тот подобрал).
Такая рекомендация описана толи у Майерся, то ли у Сатера.

Добавлено через 1 минуту и 22 секунды
Цитата

Имхо, это правило такое же, как "нельзя использовать goto". Т.е. для новичков. Когда набьет руку, то уже сам сообразит, что и когда использовать.

 smile
но в данном случае его лучше вообще не использовать, в привычку войдет

Автор: vinter 31.3.2009, 17:34
Цитата(azesmcar @  31.3.2009,  18:23 Найти цитируемый пост)
Непереносимый я сказал в том смысле что с другими контейнерами не работает

Цитата(azesmcar @  31.3.2009,  18:23 Найти цитируемый пост)
Такая рекомендация описана толи у Майерся, то ли у Сатера.

А еще у Майерса написано, что ни в коем случе не стоит пытаться писать универсально-контейнерный код, я с ним в этом полностью солидарен. 
Цитата(azesmcar @  31.3.2009,  18:23 Найти цитируемый пост)
но в данном случае его лучше вообще не использовать, в привычку войдет

в этом нет ничего плохого, я периодически использую именно такую запись. Проблем пока не видел. 
Я правда не хотел придираться, просто не надо подавать эту рекомендацию как аксиому.

Автор: azesmcar 31.3.2009, 17:37
Цитата

А еще у Майерса написано, что ни в коем случе не стоит пытаться писать универсально-контейнерный код, я с ним в этом полностью солидарен. 

не совсем так, он говорит что пытатся написать контейнерно независимый код, часто приводит к неэффективности, но в этом случае - мы ничего не делаем чтобы сделать его контейнеро-независимым..так что, по моему все таки лучше != 

Автор: C/L 1.4.2009, 07:26
Цитата(bsa @  31.3.2009,  18:39 Найти цитируемый пост)
C/L, во-первых, по правилам положено проверять условие it != verts.end(). У всех итераторов есть оператор неравно, а вот оператор меньше - только у RandomAccessIterator.

Как я понимаю ошибка в моем случае произойдет только если я поменяю тип контейнера например на list, так как у него нет RandomAccessIterator, но тогда и memcpy() не будет работать - это тоже непереносимый код. Или возможны и другие проблемы в использовании оператора <?

Цитата(bsa @  31.3.2009,  18:39 Найти цитируемый пост)
во-вторых, в общем случае it++ выполняется дольше, чем ++it. Лучше используй префиксную форму, если тебе нет потребности в постфиксной.

спасибо, учту.

Цитата(azesmcar @  31.3.2009,  18:43 Найти цитируемый пост)
что конкретно надо сделать? может найдем другое решение?

Вот и я думаю, может без копирования можно как то обойтись. Мне нужно заполнить буфер вершин, переданный устройством по указателю void*. Может можно построить вектор прямо в буфере? При этом при необходимости передать контейнеру указатель на CALLBACK функцию, изменяющую размер буфера. Для этого наверно придется свой контейнер писать... smile 

Автор: azesmcar 1.4.2009, 08:36
Цитата

Как я понимаю ошибка в моем случае произойдет только если я поменяю тип контейнера например на list, так как у него нет RandomAccessIterator, но тогда и memcpy() не будет работать - это тоже непереносимый код. Или возможны и другие проблемы в использовании оператора <?

согласен..просто чтобы привычка не выработалась..речь об общем случае.

Цитата

Вот и я думаю, может без копирования можно как то обойтись. Мне нужно заполнить буфер вершин, переданный устройством по указателю void*. Может можно построить вектор прямо в буфере? При этом при необходимости передать контейнеру указатель на CALLBACK функцию, изменяющую размер буфера. Для этого наверно придется свой контейнер писать... smile 

Код

std::copy(vec.begin(), vec.end(), reinterpret_cast<VERTEX*>(buf) );

а вот так не пойдет?

Автор: xvr 1.4.2009, 10:34
Если то, что копируется не является POD или структурой/юнионом из POD'ов (без конструктора, деструктора и виртуальных методов), то memcpy использовать нельзя  smile 

Автор: C/L 1.4.2009, 10:39
Цитата(xvr @  1.4.2009,  12:34 Найти цитируемый пост)
Если то, что копируется не является POD или структурой/юнионом из POD'ов

К сожалению не знаю что такое POD. Структура простая, но имеется конструктор, простой, никаких указателей он не инициализирует.

Добавлено через 50 секунд
Виртуальных методов тоже нету

Автор: zim22 1.4.2009, 11:00
Цитата(C/L @  1.4.2009,  10:39 Найти цитируемый пост)
К сожалению не знаю что такое POD. 

это встроенные типы данных. а не определённые пользователем. например int, long, double, long*, ...
Цитата(C/L @  1.4.2009,  10:39 Найти цитируемый пост)
но имеется конструктор

значит не подходит. т.к. конструктор занимает дополнительное место и memset "фурычить" не будет smile

Автор: C/L 1.4.2009, 11:00
Цитата(azesmcar @ 1.4.2009,  10:36)
Цитата

Вот и я думаю, может без копирования можно как то обойтись. Мне нужно заполнить буфер вершин, переданный устройством по указателю void*. Может можно построить вектор прямо в буфере? При этом при необходимости передать контейнеру указатель на CALLBACK функцию, изменяющую размер буфера. Для этого наверно придется свой контейнер писать... smile 

Код

std::copy(vec.begin(), vec.end(), reinterpret_cast<VERTEX*>(buf) );

а вот так не пойдет?

вот vector на самом деле принимает 2 параметра, первый - тип элементов. А второй зачем?
Код

template<class _Ty, class _Ax> class vector : public _Vector_val<_Ty, _Ax>

Автор: azesmcar 1.4.2009, 11:03
C/L второй алокатор, если хочешь написать свое реаспределение памяти

Автор: C/L 1.4.2009, 11:05
Цитата(zim22 @  1.4.2009,  13:00 Найти цитируемый пост)
Цитата(C/L @  1.4.2009,  10:39 )но имеется конструктор

значит не подходит. т.к. конструктор занимает дополнительное место и memset "фурычить" не будет 

правда smile ? А я не знал. Он же не виртуальный!

Добавлено через 2 минуты и 11 секунд
Цитата(azesmcar @  1.4.2009,  13:03 Найти цитируемый пост)
C/L второй алокатор, если хочешь написать свое реаспределение памяти

А с его помощью можно построить вектор где угодно? Пробывал искать по этой теме, пока ничего не нашел.

Автор: bsa 1.4.2009, 11:14
Цитата(zim22 @ 1.4.2009,  11:00)
конструктор занимает дополнительное место и memset "фурычить" не будет smile

Лучше почитать http://www.fnal.gov/docs/working-groups/fpcltf/Pkg/ISOcxx/doc/POD.html - там нет упоминаний об обычном конструкторе (только конструктор копирования). Кстати, рекомендую почитать что-нибудь про классы, так как на лицо непонимание внутренней организации объектов.

Автор: azesmcar 1.4.2009, 11:14
Цитата

значит не подходит. т.к. конструктор занимает дополнительное место и memset "фурычить" не будет smile 


чего чего?? сколько места занимает конструктор в памяти?

Добавлено @ 11:16
C/L если в классе нет динамически инициализируемых обьектов, или обьекта, который динамически инициализирует переменные - спокойно можно использовать..

Автор: bsa 1.4.2009, 11:20
Цитата(C/L @ 1.4.2009,  11:05)
Цитата(azesmcar @  1.4.2009,  13:03 Найти цитируемый пост)
C/L второй алокатор, если хочешь написать свое реаспределение памяти

А с его помощью можно построить вектор где угодно? Пробывал искать по этой теме, пока ничего не нашел.

Можно "где-угодно", но не "из-чего угодно". Т.е. аллокатор будет использоваться вместо оператора new. Думаю, тебе не это нужно.
Тебе написали уже все возможные варианты. Ну есть еще вариант без копирования - возвращать константный указатель на первый элемент вектора. Но для этого придется менять функцию, так как в нынешнем виде она подразумевает только копирование.

Автор: azesmcar 1.4.2009, 11:27
можно например написать алокатор который будет напрямую создавать твои обьекты в твоем void* буфере с помощью placement new. Но я не уверен что тебе это нужно..

Автор: bsa 1.4.2009, 11:32
Цитата(azesmcar @ 1.4.2009,  11:27)
можно например написать алокатор который будет напрямую создавать твои обьекты в твоем void* буфере с помощью placement new. Но я не уверен что тебе это нужно..

так я о том же  smile 

Автор: azesmcar 1.4.2009, 11:34
bsa smile 
я немного детализировал smile 

Автор: zim22 1.4.2009, 11:34
bsaazesmcar
по почкам просьба больно не бить, понял свою тупость про POD типы  smile 

Автор: C/L 1.4.2009, 11:52
Цитата(azesmcar @  1.4.2009,  13:27 Найти цитируемый пост)
можно например написать алокатор который будет напрямую создавать твои обьекты в твоем void* буфере с помощью placement new. Но я не уверен что тебе это нужно..

А что в этом особенного? Аллокаторы я еще не писал  smile 

Цитата(bsa @  1.4.2009,  13:20 Найти цитируемый пост)
Ну есть еще вариант без копирования - возвращать константный указатель на первый элемент вектора. Но для этого придется менять функцию, так как в нынешнем виде она подразумевает только копирование.

Об этом я еще не думал, надо попробывать.

Всем спасибо, тему можно считать закрытой.

Автор: bsa 1.4.2009, 13:06
Цитата(C/L @ 1.4.2009,  11:52)
Цитата(bsa @  1.4.2009,  13:20 Найти цитируемый пост)
Ну есть еще вариант без копирования - возвращать константный указатель на первый элемент вектора. Но для этого придется менять функцию, так как в нынешнем виде она подразумевает только копирование.

Об этом я еще не думал, надо попробывать.

Всем спасибо, тему можно считать закрытой.

Только имей в виду, что этот указатель будет жить до тех пор, пока вектор жив и к нему не применяются методы, изменяющие размер в сторону увеличения (insert, push_back, resize, reserve, например, но есть исключения - читать документацию, в части об инвалидации итераторов).

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)