1

最近我一直在尝试更新一些代码以利用标准 C++ 库函数而不是旧的 C 样式函数。特别是,我尝试执行以下操作(为简单起见,人工工作示例 - 我知道代码很难看,但它简明扼要地说明了问题):

std::vector<int> vData;
vData.push_back(10990);
vData.push_back(11990);
vData.push_back(12990);
vData.push_back(13990);

unsigned char szBuffer[100];
memset(szBuffer,0,sizeof(szBuffer));

std::copy(vData.begin(),vData.end(),szBuffer);

我期望这会以与我尝试替换的代码类似的方式运行:

memcpy(szBuffer,&vData[0],sizeof(int)*vData.size());

但是调试代码,很明显std::copy我写的代码只是写入unsigned char缓冲区的前4个字节,而不是向量中4个整数的完整位模式。有人可以告诉我我做错了什么,还是只是我不能std::copy以这种方式使用并且应该坚持使用memcpy

4

4 回答 4

5

坚持memcpystd::copy是智能的,它理解所涉及的类型并正确转换intunsigned char使用标准转换。memcpy是无知的,这就是你想要的。

于 2012-10-24T10:47:06.310 回答
2

我期待这会以与我试图替换的代码类似的方式表现......

std::copy所写的不能以类似于 astd::memcpy或的方式表现,因为的元素与 的元素std::memmove之间的类型不匹配。克服这种类型不匹配的一种方法是将其转换为:std::vector<int>unsigned char szBuffer[100]szBufferint*

std::copy(vData.begin(),vData.end(),reinterpret_cast<int*>(szBuffer));

reinterpret_cast是个人喜好问题。我宁愿看到一些尖叫“危险,危险,威尔罗宾逊!”的东西。对于可以通过隐藏但不会消除 UB 可能性的 C 样式转换调用未定义行为的东西。我(和我的项目经理霸主)可以 grep 为reinterpret_cast.

UB 的潜力在这里是真实的,因为由于对齐问题,无法保证此演员表是有效的。

另请注意,不能保证std::copy将通过memcpy或实现memmove。标准(2003 年或 2011 年)中没有一个词说std::copy需要通过memcpymemmove如果可能的话。(旁白:在我见过的每一个实现中,如果这样做会“好像”采用了幼稚的实现,std::copy则将通过这种方式实现。)std::memmove

从这里切换std::memcpystd::copy这里的唯一原因是美学。有时美学会成为阻碍。“愚蠢的一致性是小头脑的妖精。” 我建议坚持使用std::memcpy. 它完全符合您的要求,并且这种用法是安全的,因为没有重叠并且缓冲区大小合适。

于 2012-10-24T11:33:23.803 回答
1

因为标准是的行为(如果不是确切的实现) std::copy 相当于:

namespace std { 
  template< typename InIter, typename OutIter >
  OutIter std::copy( InIter begin, InIter end, OutIter outp )
  {
     for( ; begin != end; ++begin, ++outp )
     {
         *outp = *begin;
     }
     return outp;
  }
}

这意味着它逐个成员地复制,递增每个迭代器并返回输出中的下一个写入位置。

这与 memcpy 的行为不同,而 memcpy 正是您在这里真正想要的。使用 memcpy 没有任何问题(即使某个 Microsoft 编译器告诉您它不安全,但它可能是不安全的,但如果您不能正确驾驶卡车,那么驾驶卡车也是如此,这并不意味着没有人可以驾驶) .

于 2012-10-24T10:52:09.703 回答
1

要将向量的内容解释为原始内存,reinterpret_cast请使用unsigned char *

std::copy(reinterpret_cast<unsigned char *>(&*vData.begin()),
          reinterpret_cast<unsigned char *>(&*vData.end()), szBuffer);

您需要间接并获取开始和结束元素的地址,因为不能保证它vector::iterator是指针类型。

这是为数不多的有保证的安全使用reinterpret_cast.

于 2012-10-24T11:10:18.283 回答