Как безопасно скопировать содержимое std :: vector в статический массив в стиле c? - PullRequest
14 голосов
/ 11 марта 2009

Мне нужно манипулировать данными в фиксированном массиве, включая вставку в середине. Вместо того, чтобы использовать memcpy и т. Д. Я хочу использовать вектор. У меня проблемы, когда я хочу скопировать векторные элементы обратно в массив c-style. Вот код:

void tryvector()
{
    using namespace std;
    const int MAX_SIZE=16;
    BYTE myarr[MAX_SIZE]={0xb0,0x45,0x47,0xba,0x11,0x12, 0x4e};
    vector<BYTE> myvec (myarr, myarr+MAX_SIZE);
    vector<BYTE>::iterator it;

    printf("myarr pre :");
    for(int i=0;i<MAX_SIZE;++i){
        printf("%02x ", myarr[i]) ;   

    }

    printf("\nmyvec pre :")
    for(it=myvec.begin(); it<myvec.end();++it){
       cout<<hex<<static_cast<int>(*it)<<" ";

    }

    it = myvec.begin()+ 3;
    myvec.insert(it,0x5f);
    printf("\nmyvec post:");
    for(it=myvec.begin(); it<myvec.end();++it){
       cout<<hex<<static_cast<int>(*it)<<" ";


    }

    copy(myvec.begin(), myvec.end(), myarr); //???
    printf("\nmyarr post:");
    for(int i=0;i<MAX_SIZE;++i){
        printf("%02x ", myarr[i]) ;   

    }

}

Я использую против 2005 года. Вот предупреждение:

warning C4996: 'std::_Copy_opt' was declared deprecated
1>        c:\program files\microsoft visual studio 8\vc\include\xutility(2270) : see      declaration of 'std::_Copy_opt'
1>        Message: 'You have used a std:: construct that is not safe. See documentation on how to use the Safe Standard C++ Library'
1>        c:\documents and settings\mhd\my documents\tesvector.cpp(50) : see reference to function template instantiation '_OutIt  std::copy<std::_Vector_iterator<_Ty,_Alloc>,BYTE*>(_InIt,_InIt,_OutIt)' being compiled
1>        with
1>        [
1>            _OutIt=BYTE *,
1>            _Ty=BYTE,
1>            _Alloc=std::allocator<BYTE>,
1>            _InIt=std::_Vector_iterator<BYTE,std::allocator<BYTE>>
1>        ]

При запуске я получил следующую ошибку во время выполнения:


    Run-Time Check Failure #2 - Stack around the variable 'myarr' was corrupted.

Обратите внимание, что я использую вектор вместо списка или deque, потому что «средняя вставка», как в приведенном выше коде, представляет собой особую проблему. Это произойдет меньше, чем «вставка в конце» и «произвольный доступ к элементу».
Любое решение?

Любой ответ, который напоминает: «Вы используете c ++, отбросьте реализацию массива стиля c. Использовать только вектор для всей реализации массива "не очень полезно.

Спасибо.

Ответы [ 4 ]

18 голосов
/ 11 марта 2009

Проблема в том, что вы добавляете вещи в вектор, чтобы в итоге получилось больше элементов, чем было в массиве myarr, с которым вы его инициализировали.

Если вы хотите скопировать вектор обратно в массив, вам нужно уменьшить его размер:

myvec.resize( MAX_SIZE);

Или вы можете ограничить количество копируемых элементов:

copy( myvec.begin(), myvec.begin()+MAX_SIZE, myarr);

Если вы хотите, чтобы массив myarr содержал все элементы, то он должен быть больше MAX_SIZE, и вы узнали, почему люди предлагают использовать vector вместо необработанных массивов (vector s умеют расти, а массивы нет).

Обратите внимание, что хотя вы не хотите «Любого ответа, который напоминает:« Вы используете c ++, отбросьте реализацию массива стиля c. Используйте только вектор для всех реализаций массива »», вы часто можете избежать использования vector и передача &myvec[0] подпрограммам, которые ожидают необработанный массив. vector требуется хранить свои элементы непрерывно, как необработанный массив, именно по этой причине.

Поскольку вы получаете предупреждение «небезопасная операция», вы используете компилятор Microsoft. Для безопасного решения проблемы вы должны использовать алгоритм checked_copy вместо copy. Как указывает Евгений Лазин , вы можете создать проверенный итератор для массива, который будет передаваться алгоритму checked_copy.

Другие варианты обеспечения безопасности копирования, для которых не требуются расширения Microsoft, заключаются в том, чтобы обернуть массив в класс (возможно, на основе шаблонов), который отслеживает размер массива и предоставляет методы для безопасного копирования данных в массив. Может помочь что-то вроде STLSoft array_proxy template или Boost's boost::array.

3 голосов
/ 11 марта 2009

В общем, я думаю, вы могли бы сделать что-то вроде этого:

void *myarr;

if((myarr = malloc(myvec.size() * sizeof myvec[0])) != NULL)
{
  memcpy(myarr, &myvec[0], myvec.size() * sizeof myvec[0]);
  /* Do stuff with the C-style array for a while
   .
   .
   .
  */
  free(myarr);  /* Don't forget handing back the memory when done. */
}

Это выделяет новый массив в стиле C для хранения элементов вектора и копирует данные на месте. Таким образом, нет необходимости сопоставлять размеры статически.

Конечно, это общее правило, поэтому оно дает вам void * для доступа к вашему массиву C, поэтому вам нужно либо привести, либо просто изменить тип на фактический тип (BYTE в данном случае). 1008 *

1 голос
/ 12 марта 2009

Вы можете использовать вывод аргумента шаблона, чтобы найти границу массива:

template<typename T, size_t N>
size_t copy(std::vector<T> const& src, T[N] dest) {
    size_t count = std::min(N, src.size());
    std::copy(src.begin(), src.begin()+count, dest);
    return count;
 }

Отключите предупреждения Microsoft о непроверенных вещах. Они направлены на то, чтобы побудить вас написать непортативный код.

0 голосов
/ 11 марта 2009

Вы можете сделать:

memcpy(myarr, &(myvec)[0], myvec.size())

Редактировать: С точки зрения безопасности, согласно this , векторы хранят данные в смежных сегментах памяти, поэтому вы можете обращаться к ним "не только с помощью итераторов, но и с помощью смещений на обычных указателях на элементы. «

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...