2009-03-11 41 views
14

Tôi cần thao tác dữ liệu trong mảng cố định liên quan đến chèn giữa. Thay vì sử dụng memcpy, v.v. Tôi muốn sử dụng vector. Tôi gặp vấn đề khi tôi muốn để sao chép các phần tử vectơ trở lại mảng kiểu c. Dưới đây là các mã:Làm thế nào để sao chép nội dung của std :: vector thành mảng tĩnh kiểu c, an toàn?

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

    } 

} 

Tôi đang sử dụng vs 2005. Dưới đây là những cảnh báo:

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

Khi tôi chạy nó, tôi nhận được lỗi sau thời gian chạy:


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

Xin lưu ý rằng tôi sử dụng véc tơ thay vì liệt kê hoặc deque vì cách chèn 'giữa' giống như mã ở trên là juat lem. Nó sẽ xảy ra ít hơn 'chèn vào cuối' và 'truy cập ngẫu nhiên của phần tử'.
Bất kỳ giải pháp nào?

Bất kỳ câu trả lời nào giống như: "Bạn sử dụng C++, thả triển khai mảng kiểu c. Chỉ sử dụng vectơ cho tất cả triển khai mảng" không thực sự hữu ích.

Cảm ơn.

+0

Chỉ vì bạn đang sử dụng vectơ <> thay vì mảng không có nghĩa là memcpy() không xảy ra. Các phương thức vector <> dễ hiểu hơn, nhưng cũng làm như vậy, và hiệu suất sẽ kém đối với các mảng lớn. – slacy

Trả lời

18

Vấn đề là bạn đang thêm các thứ vào vectơ sao cho nó kết thúc với nhiều phần tử hơn trong mảng myarr mà bạn đã khởi tạo nó.

Nếu bạn muốn sao chép các vector trở lại vào mảng, bạn sẽ cần phải kích thước nó xuống:

myvec.resize(MAX_SIZE); 

Hoặc bạn có thể hạn chế số lượng các yếu tố bạn sao chép lại:

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

Nếu bạn muốn mảng myarr chứa tất cả các phần tử, thì cần phải lớn hơn MAX_SIZE và bạn đã tìm ra lý do tại sao mọi người đề xuất sử dụng vector thay vì mảng thô (vector s biết cách phát triển, mảng không) .

Lưu ý rằng trong khi bạn không muốn 'Bất kỳ câu trả lời nào tương tự: "Bạn sử dụng C++, thả triển khai mảng kiểu c. Chỉ sử dụng vectơ cho tất cả triển khai mảng"', bạn thường có thể sử dụng vector và chuyển &myvec[0] đến các thường trình mong đợi một mảng thô. vector là cần thiết để lưu trữ các phần tử của nó liền kề giống như một mảng thô chỉ vì lý do này.

Vì bạn đang nhận được cảnh báo 'hoạt động không an toàn', bạn đang sử dụng trình biên dịch của Microsoft. Để khắc phục sự cố một cách an toàn, bạn phải sử dụng thuật toán checked_copy thay vì copy. Là Evgeny Lazin indicates, bạn có thể tạo trình vòng lặp đã kiểm tra cho mảng của mình để chuyển sang thuật toán checked_copy.

Các tùy chọn khác để sao chép an toàn không yêu cầu phần mở rộng của Microsoft sẽ bao bọc mảng trong một lớp (có thể được sắp xếp) theo dõi kích thước mảng và cung cấp các phương pháp sao chép dữ liệu vào mảng một cách an toàn . Một cái gì đó như STLSoft's array_proxy template hoặc Boost's boost::array có thể hữu ích.

+0

Có, điều này giải quyết vấn đề thời gian chạy của bạn. –

+0

Điều này có vẻ hoạt động, nhưng cảnh báo vẫn còn đó. Có được không? – mhd

+0

lưu ý rằng bây giờ với C++ 11 cũng có std :: array –

0

Bạn có thể làm:

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

Edit: Theo như an toàn đi, theo this, vectơ lưu trữ dữ liệu trong các phân đoạn tiếp giáp của bộ nhớ, vì vậy bạn có thể truy cập chúng "không chỉ sử dụng vòng lặp mà còn sử dụng offsets trên con trỏ thông thường đến các phần tử. "

+0

Điều này sẽ có cùng một vấn đề vì myvec.size() lớn hơn myarr, Nó có vấn đề bổ sung không hoạt động như dự định nếu bạn thay đổi loại vectơ và mảng. –

+0

Có, nó chỉ khắc phục vấn đề biên dịch thời gian. –

+0

Cũng xin lưu ý rằng không an toàn khi lấy địa chỉ [0] của vectơ nếu nó trống. Các runtimes VC++ mới hơn sẽ lớn tiếng phàn nàn về điều này (và đúng như vậy, IMHO). –

3

Nói chung, tôi đoán bạn có thể làm một cái gì đó như thế này:

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

này phân bổ một mảng C-phong cách mới để chứa các phần tử của vector, và sao chép dữ liệu tại chỗ. Bằng cách này, không cần phải phù hợp với kích thước tĩnh.

Tất nhiên, điều này là chung nên nó chỉ cung cấp cho bạn void * để truy cập mảng C của bạn, vì vậy bạn cần phải truyền hoặc chỉ thay đổi loại thành loại thực tế (BYTE trong trường hợp này).

+0

Bạn có thường xuyên viết mã như thế này không? –

+0

Bạn nên sử dụng mới/delete [] thay vì malloc/miễn phí trong C++ – codymanix

1

Bạn có thể sử dụng trích lập luận mẫu để tìm ra mảng ràng buộc:

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

Tắt các cảnh báo của Microsoft về những thứ không được kiểm soát. Chúng nhằm thu hút bạn viết mã không thể chuyển đổi.

+2

+1 cho kỹ thuật. Nhưng "thu hút bạn vào viết mã không thể chuyển đổi"? MS cung cấp một triển khai phù hợp, tăng cường với các tính năng an toàn tùy chọn dễ tắt, và mọi người sẽ * phàn nàn * về nó - tuyệt vời. –

+0

Xem tham chiếu đến "Thư viện chuẩn C++ an toàn" trong cảnh báo, đó KHÔNG phải là tiêu chuẩn. Ý tưởng đằng sau nó không phải là xấu, nhưng họ nên đã được nhất quán trong việc đặt tên. Ví dụ. stdext :: checked_iterator/là/đúng tên. – MSalters

Các vấn đề liên quan