std::iterator, pointers and VC++ warning C4996

吃可爱长大的小学妹 提交于 2019-12-22 03:30:09

问题


int *arr = (int*) malloc(100*sizeof(int));
int *arr_copy = (int*) malloc(100*sizeof(int));
srand(123456789L);
for( int i = 0; i < 100; i++) {
    arr[i] = rand();
    arr_copy[i] = arr[i];
}

// ------ do stuff with arr ------

// reset arr...
std::copy(arr_copy, arr_copy+100,  arr);

while compiling this I get this warning for std::copy():

c:\program files (x86)\microsoft visual studio 10.0\vc\include\xutility(2227):
warning C4996: 'std::_Copy_impl': Function call with parameters that may be
unsafe - this call relies on the caller to check that the passed values are 
correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See 
documentation on how to use Visual C++ 'Checked Iterators'

I know how to disable/ignore the warning, but is there is a simple one liner solution to make a "checked iterator" out of an unchecked pointer? Something like (I know cout is not an unchecked pointer like int*, but just e.g.):

ostream_iterator<int>  out(cout," ");

std::copy(arr_copy, arr_copy+numElements,  out);

I don't want to write a whole new specialized class my_int_arr_output_iterator : iterator.... But can I use one of the existing iterators?

---edit---

As there are many many questions abt my usage of c-style-arrays and malloc instead of STL containers, let me just say that I'm writing a small program to test different sorting algorithms' performance and memory usage. The code snippet you see above is a specialized (original code is template class with multiple methods, testing one algorithm for different number of elements in arrays of different types) version specific to the problem.

In other words, I do know how to do this using STL containers (vector) and their iterators (vector::begin/end). What I didn't know is what I asked.

Thanks though, hopefully someone else would benefit from the answers if not me.


回答1:


The direct answer you're looking for is the stdext::checked_array_iterator. This can be used to wrap a pointer and it's length into a MSVC checked_iterator.

std::copy(arr_copy, arr_copy+100, stdext::checked_array_iterator<int*>(arr, 100) );

They also provide a stdext::checked_iterator which can wrap a non-checked container.




回答2:


This is a "Mother, may I" warning: the code is correct, but the library writer thinks you're not smart enough to handle it. Turn off stupid warnings.




回答3:


Here's one:

std::vector<int> arr(100);
std::vector<int> arr_copy(100);
srand(123456789L);
for( int i = 0; i < 100; i++) {
    arr[i] = rand();
    arr_copy[i] = arr[i];
}

//do stuff

std::copy(arr_copy.begin(), arr_copy.end(), arr.begin());



回答4:


There is a limited portable solution to this problem. It can be done with help of boost::filter_iterator adapter.

There are two limitations:

  1. The iterator is bidirectional without random access. it++ and it-- work but it+=10 doesn't.
  2. it=end(); int val = *it; is not checked and will assign garbage to val. It is only for the element past the last. Other iterator values will be checked. To workaround this limitation, I would always advance the iterator after using its value. So after consuming the last value it would point to end(). Then it=end()-1; int val1 = *it++; int val2 = *it++; // segfault or failing assert on this line. Ether way the error will not go unnoticed.

The solution:

filter_iterator uses a user defined predicate to control which elements are skipped. We can define our predicate that will not skip elements but it will assert if the iterator is out of range in debug mode. There will be no penalty to performance because when in release mode the predicate will only return true and it will be simplified out by the compiler. Below is the code:

// only header is required
#include "boost/iterator/filter_iterator.hpp"

// ...

const int arr[] = {1, 2, 3, 4, 5};
const int length = sizeof(arr)/sizeof(int);
const int *begin = arr;
const int *end = arr + length;

auto range_check = [begin, end](const int &t)
{ 
    assert(&t >= begin && &t < end ); 
    return true; 
};

typedef boost::filter_iterator<decltype(range_check), const int *> CheckedIt;

std::vector<int> buffer;
std::back_insert_iterator<std::vector<int>> target_it(buffer);
std::copy(CheckedIt(range_check, begin, end), CheckedIt(range_check, end, end), target_it);
for(auto c : buffer)
    std::cout << c << std::endl;

auto it = CheckedIt(range_check, begin, end);

it--; // assertion fails

auto it_end = CheckedIt(range_check, end-1, end);
it ++;

std::cout << *it; // garbage out
it ++; // assertion fails.



回答5:


For portability you could use

template <class T>
T* cloneArray(T *a, int length) {
  T *b = new T[length];
  for (int i = 0; i < length; i++) b[i] = a[i];
  return b;
}

You can tweak it to change the behaviour to copy one array to another.



来源:https://stackoverflow.com/questions/12062262/stditerator-pointers-and-vc-warning-c4996

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!