【问题标题】:std::iterator, pointers and VC++ warning C4996std::iterator、指针和 VC++ 警告 C4996
【发布时间】:2023-03-09 08:35:01
【问题描述】:
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.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'

我知道如何禁用/忽略警告,但是是否有一种简单的单行解决方案可以从未检查的指针中生成“检查的迭代器”?类似的东西(我知道 cout 不是像 int* 这样的未经检查的指针,而只是例如):

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

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

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

---编辑---

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

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

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

【问题讨论】:

  • 你在 c++ 中使用 malloc 有什么原因吗?
  • 您应该使用std::vector&lt;int&gt;,除了使您的代码更安全、更易于推理之外,它恰好可以解决您的问题。就个人而言,我总是在任何新项目开始时禁用该警告。
  • @GManNickG:我不能使用矢量。见编辑。

标签: c++ algorithm stl iterator


【解决方案1】:

这个问题有一个有限的便携式解决方案。 可以在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.

【讨论】:

    【解决方案2】:

    为了便携性,您可以使用

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

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

    【讨论】:

    • 一年多了..!您的建议并不完全是一个班轮……但感谢您的关注并欢迎来到 SO。 :)
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

      std::copy(arr_copy, arr_copy+100, stdext::checked_array_iterator&lt;int*&gt;(arr, 100) );

      他们还提供了一个stdext::checked_iterator,它可以包装一个未检查的容器。​​

      【讨论】:

      • @thekashyap:好吧,我认为任何解决方案都是不可移植的,因为这种检查迭代器的风格是 MSVC 的东西,我希望解决方案也是如此。
      • 自 MSVS 2010 起,他们不再拥有 stdext::checked_iterator。只有 MSVS 2005 和 2008 做到了。然而checked_array_iterator 在那里并且运行良好。
      【解决方案5】:

      这是一个:

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

      【讨论】:

      • 虽然没有真正回答这个问题。我很好奇是否有办法真正“修复”这个警告而不是沉默或颠覆它。
      • @GManNickG 这仍然会产生警告吗? (未检查)
      • 如果有兴趣,可以将三行if语句替换为std::generate(arr.begin(), arr.end(), rand)
      • @MooingDuck 谢谢!学到了!我知道存在这样的事情(事先查看了std::fill):)
      • @LuchianGrigore,谢谢。我知道这是可能的,但它没有回答我的问题“是否有一个简单的单行解决方案可以用未检查的指针创建一个“检查的迭代器”?”。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-03
      • 2015-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多