std::迭代器、指针和 VC++ 警告 C4996


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

在编译时,我收到以下警告std::copy()

c:program files (x86)microsoft visual studio 10.0vcincludexutility(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'

我知道如何禁用/忽略警告,但是是否有一个简单的单行解决方案可以从未经检查的指针中制作"已检查的迭代器"?像这样的东西(我知道cout不是像int*那样未经检查的指针,而只是例如(:

ostream_iterator<int>  out(cout," ");
std::copy(arr_copy, arr_copy+numElements,  out);

我不想写一个全新的专业class my_int_arr_output_iterator : iterator....但是我可以使用现有的迭代器之一吗?

---编辑---

由于我使用 c-style-array 和 malloc 而不是 STL 容器有很多问题,我只想说我正在编写一个小程序来测试不同排序算法的性能和内存使用情况。您在上面看到的代码片段是特定于问题的专用版本(原始代码是具有多种方法的模板类,针对不同类型的数组中不同数量的元素测试一种算法(。

换句话说,我确实知道如何使用 STL 容器(vector(及其迭代器(vector::begin/end(来做到这一点。我不知道的是我问的。

不过谢谢,如果不是我,希望其他人会从答案中受益。

您正在寻找的直接答案是 stdext::checked_array_iterator。这可用于将指针及其长度包装到 MSVC checked_iterator中。

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

它们还提供 stdext::checked_iterator,可以包装未经检查的容器。

这是一个"母亲,我可以"的警告:代码是正确的,但库编写者认为你不够聪明,无法处理它。关闭愚蠢的警告。

这是一个:

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

此问题的便携式解决方案有限。它可以在 boost::filter_iterator 适配器的帮助下完成。

有两个限制:

  1. 迭代器是双向的,没有随机访问。 it++it--有效,但it+=10不起作用。
  2. it=end(); int val = *it;未选中,会将垃圾分配给 val。它仅适用于超过最后一个元素的元素。将检查其他迭代器值。为了解决此限制,我总是在使用迭代器的值后推进迭代器。因此,在消耗最后一个值后,它将指向 end((。然后it=end()-1; int val1 = *it++; int val2 = *it++; // segfault or failing assert on this line.以太方式的错误不会被忽视。

解决方案:

filter_iterator使用用户定义的谓词来控制跳过哪些元素。我们可以定义我们的谓词,它不会跳过元素,但它会断言迭代器是否在调试模式下超出范围。不会对性能造成任何影响,因为在发布模式下,谓词只会返回 true,并且编译器会将其简化。下面是代码:

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

为了便于移植,你可以使用

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

您可以调整它以更改将一个数组复制到另一个数组的行为。

最新更新