【问题标题】:error C4996: 'std::_Copy_impl': Function call with parameters that may be unsafe错误 C4996:“std::_Copy_impl”:使用可能不安全的参数调用函数
【发布时间】:2013-10-05 10:42:46
【问题描述】:

我知道这个问题在 SO 中被问过很多次,但这与其他问题有所不同。

Compiler Error: Function call with parameters that may be unsafe

Visual Studio Warning C4996

xutility(2227): warning C4996: 'std::_Copy_impl'

失败的代码片段

DWORD dwNumberOfNames = pExportDirectory->NumberOfNames;
LPDWORD dwNames = (LPDWORD)((LPBYTE)hDLL +  pExportDirectory->AddressOfNames);
std::vector< std::string > exports;
std::copy(
    dwNames, 
    dwNames + dwNumberOfNames, 
    [&exports, &hDLL](DWORD  dwFuncOffset)
{
    std::string fname = std::string((PCHAR)((PBYTE)hDLL + dwFuncOffset));
    exports.push_back(fname);
}
);

编译器错误

错误 1 ​​错误 C4996:“std::_Copy_impl”:带参数的函数调用 这可能是不安全的——这个调用依赖于调用者来检查 传递的值是正确的。要禁用此警告,请使用 -D_SCL_SECURE_NO_WARNINGS。请参阅有关如何使用 Visual C++ 'Checked Iterators' C:\Program Files (x86)\Microsoft Visual Studio 的文档 11.0\VC\include\xutility 2176

问题

考虑到C4996,表示该函数被标记为已弃用 问题出在哪里?

  1. MS 认为使用 std::copy 是不安全的,会被弃用吗?
  2. 是因为我使用了std::copyC Array
  3. 是因为我使用 Lambda 表达式的方式吗?
  4. 如果不推荐使用 std::copy,如果我需要便携,还有什么替代方法。

注意

我知道,如何抑制警告,但我很想知道问题的根本原因?

另外,对我来说同样重要的是,在不影响代码质量的情况下处理此问题的可移植方式。

【问题讨论】:

  • std::copy 的第三个参数应该是一个输出迭代器,但是你有一个不返回迭代器的 lambda。
  • (1) :使用std::copy,您不确定是否有足够的“位置”用于输出迭代器,因此可能存在缓冲区溢出。
  • @Jarod42 请参阅下面的答案,如果您将std::back_inserter 与标准容器一起使用,则不会出现溢出问题。

标签: c++ visual-c++ visual-studio-2012 c++11


【解决方案1】:

根据 msdn:http://msdn.microsoft.com/en-us/library/x9f6s1wf.aspx,您没有调用 std::copy

那个函数签名是这样的:

template<class InputIterator, class OutputIterator> 
   OutputIterator copy( 
      InputIterator _First,  
      InputIterator _Last,  
      OutputIterator _DestBeg 
   );

那里没有放置仿函数/lambda的地方。

你也没有打电话给std::copy_ifhttp://msdn.microsoft.com/en-us/library/ee384415.aspx

template<class InputIterator, class OutputIterator, class BinaryPredicate>
   OutputIterator copy_if(
      InputIterator _First, 
      InputIterator _Last,
      OutputIterator _Dest,
      Predicate _Pred
    );

因为您没有输出迭代器,您的谓词也不会返回布尔值。

看起来你想要std::transform:http://msdn.microsoft.com/en-us/library/391xya49.aspx

template<class InputIterator, class OutputIterator, class UnaryFunction> 
   OutputIterator transform( 
      InputIterator _First1,  
      InputIterator _Last1,  
      OutputIterator _Result, 
      UnaryFunction _Func 
   ); 

你应该在输出迭代器中返回你想要的值。所以它会是这样的:

std::transform(
    dwNames, 
    dwNames + dwNumberOfNames,
    std::back_inserter(exports),
    [&hDLL](DWORD  dwFuncOffset) // This lambda is WRONG
{
    // THIS LINE IS WRONG 
    std::string fname = std::string((PCHAR)((PBYTE)hDLL + dwFuncOffset));
    return fname;
}
);

我的 lambda 是错误的。您需要输入数组的 ELEMENTS(我不确定类型)作为 lambda 的参数,并返回您想要插入到 exports 向量中的内容。

您可能也不知道back_inserter。它在 &lt;iterator&gt; 标头中。见这里:http://msdn.microsoft.com/en-us/library/12awccbs.aspx 和这里:http://www.cplusplus.com/reference/iterator/back_inserter/

这可能不是 100% 的答案,但有了它,我认为你可以到达你想去的地方。

【讨论】:

  • 他好像在用std::for_each
【解决方案2】:

这不是std::copy 本身,我认为您的问题是使用 LPDWORD 进行复制,这使得 Visuall C++ 认为您正在执行 C 字符串复制,因为 LPDWORD 不是已检查的迭代器。

http://msdn.microsoft.com/en-us/library/ttcz0bys(v=vs.120).aspx

【讨论】:

  • 感谢您的回答。你的猜测有理由吗?编译器错误指的是 std::_Copy_impl,而不是 strcpy。您在哪里看到对 strcpy 的调用?
  • 问题中出现的消息强烈表明它 std::copy 本身被警告,而且问题不使用char *(不是无论如何,警告在哪里)。
  • 我之前使用 strcpy、strlen 等也有过这个警告。我刚刚检查过,这个警告是因为你没有使用检查过的迭代器。
  • @JohnSmith:checked iterator 是 C++ 标准的一部分,还是特定于 MS 的?这会使我的代码可移植吗?将 stdext::checked_array_iterator 与 lambda 表达式一起使用的正确方法是什么?
  • 我认为检查迭代器是特定于 MS 的。 stdext 我相信来自 MS。我不知道 lambda 部分的答案。
猜你喜欢
  • 1970-01-01
  • 2016-07-24
  • 1970-01-01
  • 2012-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-15
  • 1970-01-01
相关资源
最近更新 更多