tags:

views:

2379

answers:

4

I need to manipulate data in fixed array involving mid insertion. Rather than using memcpy,etc. I want to use vector. I have problem when I want to copy the vector elements back to the c-style array. Here's the code:

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]) ;   

    }

}

I'm using vs 2005. Here's the warning:

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>        ]

When I run it , I got the following run-time error:


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

Please note that I use vector instead list or deque because the 'middle insertion' like the code above is juat a particular problem. It will happen less than 'inserting at the end' and 'random access of element'.
Any solution ?

Any answer that resembles:"You use c++, drop the c style array implementation. Use only vector for all array implementation" is not really helpful.

Thanks.

A: 

You can do:

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

Edit: As far as safety goes, according to this, vectors store data in contiguous segments of memory, so you can access them "not only using iterators but also using offsets on regular pointers to elements."

jeffamaphone
This will have the same problem since myvec.size() is larger than myarr, It has the additional problem of not working as intended if you change the type of the vector and the array.
Michael Burr
Yes, it only fixes the compile-time issue.
jeffamaphone
Also keep in mind that it's not safe to take the address of [0] of a vector if it is empty. The newer VC++ runtimes will loudly complain about this (and rightly so, IMHO).
Timo Geusch
You assume that sizeof(BYTE) is 1. I know intatively it should be, but not a an assumption I would rely on.
Martin York
Well I don't know what BYTE is (I don't do Windows), but by definition, sizeof(char) == 1 in C++.
Brian Neal
Timo: If its empty, wouldn't .size() return zero and memcpy copy 0 bytes, in which case it doesn't matter if its invalid?Martin: Well yes, obviously if sizeof(BYTE) isn't 1 you have to multiply by sizeof the type at the end. I mean, we memcpy might be #define'd to be HaltAndCatchFire() OMFG!!
jeffamaphone
+6  A: 

The problem is that you're adding things to the vector so it ends up with more elements than were in the myarr array that you initialized it with.

If you want to copy the vector back into the array, you'll need to size it down:

myvec.resize( MAX_SIZE);

Or you could limit the number of elements you copy back:

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

If you want the myarr array to contain all the elements, then it needs to be larger than MAX_SIZE, and you've found out why people suggest to use vector rather than raw arrays (vectors know how to grow, arrays do not).

Note that while you don't want 'Any answer that resembles:"You use c++, drop the c style array implementation. Use only vector for all array implementation"', you can often get away with using a vector and passing &myvec[0] to routines that expect a raw array. vector is required to store its elements contiguously just like a raw array for just this reason.

Since you're getting the 'unsafe operation' warning, you're using Microsoft's compiler. To fix the problem safely, you're supposed to use the checked_copy algorithm instead of copy. As Evgeny Lazin indicates, you can create a checked iterator for your array to pass to the checked_copy algorithm.

Other options to make the copy safe that do not require Microsoft extensions would be to wrap the array in a class (possibly templated) that keeps track of the array size and provides methods to copy data into the array in a safe manner. Something like STLSoft's array_proxy template or Boost's boost::array might help.

Michael Burr
Yes, this solves your runtime issue.
jeffamaphone
This seems works, but the warning is still there. Is that okay?
mhd
A: 

In general, I guess you could do something like this:

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. */
}

This allocates a new C-style array to hold the vector's elements, and copies the data in place. This way the there is no need to match the sizes statically.

Of course, this is general so it just gives you a void * to access your C array with, so you need to either cast or just change the type to the actual type (BYTE in this case).

unwind
Do you regularly write code like this?
1800 INFORMATION
+2  A: 

You can use template argument deduction to find the array bound:

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;
 }

Turn off the Microsoft warnings about unchecked stuff. They're aimed at luring you into writing unportable code.

MSalters
+1 for technique. But "luring you into writing unportable code"? MS provides a conforming implementation, augmented with optional safety features that are easy to turn off, and people will *complain* about it -- amazing.
j_random_hacker
See reference to "Safe Standard C++ Library" in the warning, that is NOT a standard. The idea behind it isn't that bad, but they should have been consistent in the naming. E.g. stdext::checked_iterator /is/ properly named.
MSalters