为什么在使用g++ 4.8.4时,这段代码会产生一个包含单个元素的map ?
Why, when using g++ 4.8.4, does this code result in a map with a single element?
在过去一年半的时间里,我一直参与将一个较旧的Win32-MFC项目移植到Linux上,最终遇到了一些我不完全理解的东西。起初,我认为这可能是由于引入了c++ 11移动语义,但我不确定这是否是问题所在。在g++ 4.8.4下使用-std=c++11标志执行以下代码:
#include <map>
#include <string>
#include <iostream>
#include <iomanip>
#include <cstring>
const char* foo[] = { "biz", "baz", "bar", "foo", "yin" };
const int sizes[] = { 3, 3, 3, 3, 3 };
typedef std::map <std::string, int> simpleMap_t;
typedef std::pair<std::string, int> simplePair_t;
int main()
{
simpleMap_t map;
std::string key;
for (int i = 0; i<5; i++)
{
key.resize(sizes[i]);
memcpy(const_cast<char *>(key.data()), foo[i], sizes[i]);
simplePair_t pair = std::make_pair(key, 0);
std::cout << "key: "" << key << "" - " << static_cast<const void*>(key.data())
<< " pair.first: "" << pair.first << "" - " << static_cast<const void*>(pair.first.data())
<< std::endl;
map.insert(map.end(), pair);
}
std::cout << "map size = " << map.size() << std::endl;
return 0;
}
将产生如下输出:
key: "biz" - 0x1dec028 pair.first: "biz" - 0x1dec028
key: "baz" - 0x1dec028 pair.first: "baz" - 0x1dec028
key: "bar" - 0x1dec028 pair.first: "bar" - 0x1dec028
key: "foo" - 0x1dec028 pair.first: "foo" - 0x1dec028
key: "yin" - 0x1dec028 pair.first: "yin" - 0x1dec028
map size = 1
而在Visual Studio 2013中编译的相同代码将生成如下:
key: "biz" - 0039FE14 pair.first: "biz" - 0039FDE0
key: "baz" - 0039FE14 pair.first: "baz" - 0039FDE0
key: "bar" - 0039FE14 pair.first: "bar" - 0039FDE0
key: "foo" - 0039FE14 pair.first: "foo" - 0039FDE0
key: "yin" - 0039FE14 pair.first: "yin" - 0039FDE0
map size = 5
有趣的是,当每次迭代都改变字符串的大小时,用g++编译的代码将"工作"。替换:const char* foo[] = { "biz", "baz", "bar", "foo", "yin" };
const int sizes[] = { 3, 3, 3, 3, 3 };
:
const char* foo[] = { "bizbiz", "baz", "barbar", "foo", "yinyin" };
const int sizes[] = { 6, 3, 6, 3, 6 };
会产生:
key: "bizbiz" - 0xc54028 pair.first: "bizbiz" - 0xc54028
key: "baz" - 0xc54098 pair.first: "baz" - 0xc54098
key: "barbar" - 0xc54108 pair.first: "barbar" - 0xc54108
key: "foo" - 0xc54178 pair.first: "foo" - 0xc54178
key: "yinyin" - 0xc541e8 pair.first: "yinyin" - 0xc541e8
map size = 5
我对移动语义的理解是不完整的,但我想知道这是否是在这里起作用的。在创建std::pair时,内部std::string缓冲区的所有权是否被放弃?或者它是否像std::string::resize()方法中的优化一样,在应该重新分配新的字符缓冲区时没有重新分配?
由于以下奇怪的代码行,您的代码有未定义的行为:
key.resize(sizes[i]);
memcpy(const_cast<char *>(key.data()), foo[i], sizes[i]);
几乎任何时候你发现自己需要抛弃const
-ness(并且,就这件事而言,使用memcpy
), 你做错了。
确实,粗略地看一下std::string::data
的文档(你读过,对吧?对吧?)确认:
修改通过
data
访问的字符数组是[sic]未定义的行为。
老式的作业有什么问题吗?
key.assign(foo[i], sizes[i]);`
由于UB,进一步分析这个是愚蠢的。
相关文章:
- 使用一个考虑到std::map中键值的滚动或换行的键
- 为什么在 std::map 上移动无法将元素从一个映射移动到另一个映射
- 使用 map.end() 访问 map 的最后一个元素
- 如何创建一个模板化函数,可以在任何具有字符串键的 std::map 上运行?
- 如何有效地将(一些)项目从一个std::map移动到另一个std::map
- 创建一个变体类和 std::map<变体,变体>
- 当 map 是一个整数数组并且由 operator[] 创建时,它是否初始化其映射类型
- 为什么我可以将 std::map 的键传递给一个期望非常量的函数?
- Visual Studio 2017 STL 可视化工具失败了一个 std::map<MyIntrusivePtr, std::tuple<....> >
- 如何构建一个 Map,其中键是抽象基类(而不是值)
- 为什么 std::map emplace 需要在 gcc 上有一个复制构造函数
- 为什么STD :: MAP需要操作员&lt;以及我如何写一个
- 将字符指针按顺序存储在 map 中 std::map<char*, int> mymap。将其存储为字符或字符串不是一个选项
- 为什么std :: map中有一个分类机制
- 动态创建一个继承的类,使用STD :: MAP使用基类指针访问
- 如何在STD :: MAP中找到具有至少一个数据成员等于密钥的结构的元素
- 一个类用于集合和字典 (map)
- 检查map<string,string>是否包含另一个map<string,string>
- std::map插入另一个map
- 在c++中使用一个map中的值作为另一个map中的键