【问题标题】:Wrapping pointers into an iterator for copying into an STL container将指针包装到迭代器中以复制到 STL 容器中
【发布时间】:2015-10-22 13:09:07
【问题描述】:

我有一个指向我想放入字符串中的一些数据的指针。我认为使用std::copy 应该是最安全的方法。

但是,在 Visual Studio 2010 中我收到警告

警告 C4996:“std::_Copy_impl”:带有可能不安全参数的函数调用 - 此调用依赖于调用者检查传递的值是否正确。要禁用此警告,请使用 -D_SCL_SECURE_NO_WARNINGS。

当然警告是正确的。在MSDN checked_array_iterator 上描述了一些checked_array_iterator 对象,它们可用于包装这样的指针并使其与STL 迭代器兼容。

问题是,这个checked_array_iterator 只能用作目标,不能用作源。

所以当我尝试这样使用它时,应用程序崩溃或无法编译:

char buffer[10] = "Test";
std::string s;

// These are parameters from an external call and only shown here to illustrate the usage.
char *pTargetAdress = &s;
const char *oBegin = buffer;
const char *oEnd = oBegin+sizeof(buffer);

std::string *p = reinterpret_cast<std::string *>(pTargetAdress);
std::copy(oBegin, oEnd, p->begin());   // crash

stdext::checked_array_iterator<const char *>beg(oBegin, oEnd-oBegin);
stdext::checked_array_iterator<const char *>end(oEnd, 0);
std::copy(beg, end, p->begin());   // crash

stdext::checked_array_iterator<const char *>v(oBegin, oEnd-oBegin);
std::copy(v.begin(), v.end(), p->begin());   // doesn't compile

如果有可移植的标准方式,我宁愿使用它而不是在 MS 扩展上使用。

【问题讨论】:

  • 肯定有一个string::assign 可以将你的缓冲区作为参数,有或没有缓冲区大小。
  • @BoPersson,是的,你是对的。这就是我现在使用的。

标签: c++ stl iterator


【解决方案1】:

指针是非常好的(随机访问)迭代器。问题在于您将数据复制到坏内存中。 p-&gt;begin() 等于 s.begin() 等于 s.end() 指向无效内存。要解决此问题,您可以使用例如

std::string *p = reinterpret_cast<std::string *>(pTargetAdress);
p->resize(oEnd - oBegin); //resize to make room for the data
std::copy(oBegin, oEnd, p->begin());   // no more crash

或者

#include <iterator>

std::string *p = reinterpret_cast<std::string *>(pTargetAdress);
std::copy(oBegin, oEnd, std::back_inserter(*p));   // copy by appending to the end

或者干脆

std::string *p = reinterpret_cast<std::string *>(pTargetAdress);
*p = std::string(oBegin, oEnd);   // copy by temporary

【讨论】:

  • 我认为该副本会创建所需的房间,所以我没有使用调整大小。谢谢!
  • 我最终按照评论的建议使用了assign,但是这个答案也有效并且符合我想要的精神,因为我不想创建一个中间字符串来复制.
【解决方案2】:

在您的具体情况下,您可以使用std::string 构造函数或assign() 方法,请参阅cppreference

const char* pointer = ...;
std::size_t size = ...;

std::string string(pointer, size);
std::string string(pointer); // if null-terminated

顺便说一句,从void* 转换为T* 时,您应该使用static_cast 而不是reinterpret_cast

一般:

如果有可移植的标准方式,我宁愿使用它而不是在 MS 扩展上使用。

这是 Visual Studio 2015 中最令人讨厌的警告之一。虽然它的消息正确的,但对于在原始指针上使用 std::copy() 的每个人来说应该是显而易见的。 checked_array_iterator 提出的解决方法不仅完全过度设计了一个简单的问题,而且还引入了非标准类,从而使您的代码不可移植。

如果我是你,我会定义 _SCL_SECURE_NO_WARNINGS 并让完全有效的 C++ 代码再次编译而不会出现警告。

【讨论】:

  • 在原始代码中它是一个 (char *) 所以我必须使用重新解释。将其翻译为帖子中的示例时出错。
  • 添加 const 限定符不需要强制转换,尤其是 reinterpret_cast。你到底做了什么,你得到了什么错误?
  • char *pTargetAdress; static_cast<:string>(pTargetAdress); => char * 不能通过静态转换转换为 std::string *。我的意思是在示例中使用 void 指针是我在翻译到发布过程中的一个错误。我更正了问题以反映这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-12-05
  • 1970-01-01
  • 1970-01-01
  • 2012-07-11
  • 2012-01-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多