我有一张我根据需要填写的地图。要将地图的内容输出到另一个变量中,我使用的是memcpy。
如果memcpy行被注释,我看到输出打印正确显示。 100 => 1234水果
如果我取消注释memcpy,我会看到以下错误。之前看到的打印也不会显示。
块释放两次
退出:ExitFailure 127
#include <iostream>
#include <map>
#include <string>
struct apple
{
int iValue;
std::string str1;
};
typedef std::map<int, apple> AppleMap;
int main()
{
AppleMap one;
apple structaa;
structaa.iValue = 1234;
structaa.str1 = "Fruits";
int value = 100;
one[value]=structaa;
AppleMap::iterator it = one.find(100);
if(it != one.end())
{
std::cout << it->first << " => " << it->second.iValue << '\t' << it->second.str1 << '\n';
}
else
{
std::cout << "Value Not Found\n";
}
apple structbb;
memcpy(&structbb, &(it->second), sizeof(apple));
return 0;
}
我做错了什么帮助?
答案 0 :(得分:4)
您无法使用apple
复制“深层”结构(例如memcpy
)。你的apple
结构深度的原因是它包含一个std::string
,它在堆上有内存。当您使用memcpy
复制std::string
时,您正在复制指向堆的指针,但现在您有两个结构(一个structbb
和一个在地图内指向堆上的相同内存
正确的做法是直接复制structbb
,不要使用memcpy
,即
structbb = it->second;
这将使用默认的复制方法,该方法将使用他们的定义的复制方法复制每个成员。字符串成员str1
的默认复制方法是安全的,这意味着复制的字符串指向 new 堆内存位置,以便可以安全地销毁旧字符串而不会影响新字符串
您还希望将此行移至if(it != one.end()
块的保护范围内。否则,如果您收到“未找到值”,it->second
将是假的。
答案 1 :(得分:1)
在内部,std::string
存储指向堆内存的指针。
使用apple
将apple
复制到另一个std::copy
时,复制到结构中的std::string
将包含指向与{相同的内存位置的指针复制的结构中的{1}}。
因此,当结构被破坏时,std::string
都会尝试释放相同的内存。这就是为什么你得到“块释放两次”的错误。
正如Paul R在评论中指出的那样,解决方案是使用能正确处理std::string
复制的作业:
std::string