std :: iterator,指针和VC ++警告C4996

时间:2012-08-21 20:08:03

标签: c++ algorithm stl iterator

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

换句话说,我确实知道如何使用STL容器(向量)及其迭代器(vector :: begin / end)来完成此操作。我不知道的是我问

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

5 个答案:

答案 0 :(得分:16)

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

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

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

答案 1 :(得分:7)

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

答案 2 :(得分:6)

这是一个:

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

答案 3 :(得分:1)

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

有两个限制:

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

    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.
    

答案 4 :(得分:0)

为了便于携带,您可以使用

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

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