- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我刚刚失去了三天的生命来追踪一个非常奇怪的错误,其中 unordered_map::insert() 破坏了您插入的变量。这种非常不明显的行为只发生在最近的编译器中:我发现 clang 3.2-3.4 和 GCC 4.8 是唯一编译器来展示这个“特性”。
以下是我的主要代码库中的一些简化代码,用于演示该问题:
#include <memory>
#include <unordered_map>
#include <iostream>
int main(void)
{
std::unordered_map<int, std::shared_ptr<int>> map;
auto a(std::make_pair(5, std::make_shared<int>(5)));
std::cout << "a.second is " << a.second.get() << std::endl;
map.insert(a); // Note we are NOT doing insert(std::move(a))
std::cout << "a.second is now " << a.second.get() << std::endl;
return 0;
}
我可能和大多数 C++ 程序员一样,希望输出看起来像这样:
a.second is 0x8c14048
a.second is now 0x8c14048
但是使用 clang 3.2-3.4 和 GCC 4.8 我得到了这个:
a.second is 0xe03088
a.second is now 0
这可能没有任何意义,直到您仔细检查 http://www.cplusplus.com/reference/unordered_map/unordered_map/insert/ 处的 unordered_map::insert() 文档其中 2 号重载是:
template <class P> pair<iterator,bool> insert ( P&& val );
这是一个贪婪的通用引用移动重载,消耗与任何其他重载不匹配的任何内容,并将其移动构造到 value_type。那么为什么我们上面的代码选择了这个重载,而不是大多数人所期望的 unordered_map::value_type 重载呢?
答案让你眼前一亮:unordered_map::value_type 是一对<const int, std::shared_ptr> 编译器会正确地认为一对<int, std::shared_ptr> 不可转换。因此,编译器选择移动通用引用重载,这会破坏原始的,尽管程序员不使用 std::move() 这是表明您可以接受变量被破坏的典型约定。因此,根据 C++11 标准,插入破坏行为实际上正确,而旧的编译器不正确。
您现在可能明白为什么我花了三天时间来诊断这个错误。在插入到 unordered_map 中的类型是在源代码术语中定义得很远的 typedef 的大型代码库中一点也不明显,而且任何人从未想过检查 typedef 是否与 value_type 相同。
所以我对 Stack Overflow 的问题:
为什么旧编译器不会像新编译器那样销毁插入的变量?我的意思是,即使 GCC 4.7 也没有这样做,而且它非常符合标准。
这个问题是否广为人知,因为升级编译器肯定会导致以前可以工作的代码突然停止工作?
C++ 标准委员会是否有意采取这种行为?
您如何建议修改 unordered_map::insert() 以提供更好的行为?我问这个是因为如果这里有支持,我打算将此行为作为 N 注释提交给 WG21,并要求他们实现更好的行为。
最佳答案
正如其他人在评论中指出的那样,“通用”构造函数实际上并不应该总是从它的参数中移动。如果参数真的是一个右值,它应该移动,如果它是一个左值,它应该复制。
您观察到的行为总是移动,是 libstdc++ 中的一个错误,现在根据对该问题的评论已修复。对于那些好奇的人,我看了一下 g++-4.8 header 。
bits/STL_map.h
,第 598-603 行
template<typename _Pair, typename = typename
std::enable_if<std::is_constructible<value_type,
_Pair&&>::value>::type>
std::pair<iterator, bool>
insert(_Pair&& __x)
{ return _M_t._M_insert_unique(std::forward<_Pair>(__x)); }
bits/unordered_map.h
,第 365-370 行
template<typename _Pair, typename = typename
std::enable_if<std::is_constructible<value_type,
_Pair&&>::value>::type>
std::pair<iterator, bool>
insert(_Pair&& __x)
{ return _M_h.insert(std::move(__x)); }
后者在应该使用 std::forward
的地方错误地使用了 std::move
。
关于c++ - C++ 标准委员会是否打算在 C++11 中 unordered_map 破坏它插入的内容?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21520308/
我最近在读 CSAPP。在 10.9 节中,它说标准 I/O 不应该与 socket 一起使用,原因如下: (1) The restrictions of standard I/O Restricti
似乎是一个足够标准的问题,可以保证解决方案中的标准设计: 假设我想在文件中写入 x+2(或更少)个字符串。 x 字符串构成一个部分的内容,这两个字符串构成该部分的页眉和页脚。要注意的是,如果内容中没有
代码版本管理 在项目中,代码的版本管理非常重要。每个需求版本的代码开发在版本控制里都应该经过以下几个步骤。 在master分支中拉取该需求版本的两个分支,一个feature分支,
我有以下sql查询,我需要获取相应的hibernate条件查询 SELECT COUNT(DISTINCT employee_id) FROM erp_hr_payment WHERE payment
所以我正在编写一些代码,并且最近遇到了实现一些 mixin 的需要。我的问题是,设计混音的正确方法是什么?我将使用下面的示例代码来说明我的确切查询。 class Projectile(Movable,
我的环境变量包含如下双引号: $echo $CONNECT_SASL_JAAS_CONFIG org.apache.kafka.common.security.plain.PlainLoginModu
示例: /** * This function will determine whether or not one string starts with another string. * @pa
有没有办法在 Grails 中做一个不区分大小写的 in 子句? 我有这个: "in"("name", filters.tags) 我希望它忽略大小写。我想我可以做一个 sqlRestriction
我搜索了很长时间,以查找将哪些boost库添加到std库中,但是我只找到了一个新库的完整列表(如此处:http://open-std.org/jtc1/sc22/wg21/docs/library_t
我已经通过使用这个肮脏的黑客解决了我的问题: ' Filter managerial functions ActiveSheet.Range("$A$1:$BW$2211").Auto
因此,我很难理解我需要遵循的标准,以便我的 Java 程序能够嵌入 HTML。我是否只需将我的主类扩展到 Applet 类,或者我还需要做更多的事情吗?另外,在我见过的每个 Applet 示例中,它都
我对在 Hibernate 中使用限制有疑问。 我必须创建条件,设置一些限制,然后选择日期字段最大值的记录: Criteria query = session.createCriteria(Stora
我有标准: ICriteria criteria = Session.CreateCriteria() .SetFetchMode("Entity1", FetchMo
我很难编写条件来选择所有子集合或孙集合为空的实体。我可以将这些作为单独的条件来执行,但我无法将其组合成一个条件。 类结构: public class Component { p
@Entity class A { @ManyToMany private List list; ... } @Entity class B { ... } 我想使用条件(不是 sql 查询)从 A
我的数据库中有以下表结构: Table A: Table B: Table C: _______________
请帮助我: 我有下一张 table : 单位 ID 姓名 用户 ID 姓名 利率 单位 ID 用户 ID 我不明白如何从 SQL 创建正确的条件结构: 代码: SELECT * FROM Unit W
我正在构建一个包含项目的网站,每个项目都有一个页面,例如: website.com/book/123 website.com/film/456 website.com/game/789 每个项目都可以
我需要使用两个属性的组合来过滤结果列表。一个简单的 SQL 语句如下所示: SELECT TOP 10 * FROM Person WHERE FirstName + ' ' + LastName L
我有一个“ super 实体”SuperEntity 和三个扩展父类(super class)的实体 ChildEntity1、...、ChildEntity3。 搜索数据库中的所有实体很容易,即我们
我是一名优秀的程序员,十分优秀!