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

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

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

4

5 回答 5

17

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

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

他们还提供了一个stdext::checked_iterator可以包装一个非检查容器。

于 2012-08-21T21:17:08.920 回答
8

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

于 2012-08-22T00:18:03.503 回答
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());
于 2012-08-21T20:11:10.857 回答
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.
于 2015-05-15T12:51:06.207 回答
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;
}

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

于 2013-10-16T10:02:15.110 回答