C++ map/unordered_map元素类型std::pair<const key_type, mapped_type>陷阱

在开发的过程中需要遍历一个unordered_map然后把他的迭代器传给另一个对象:

class A;
class B {
public:
	void deal(const std::pair<int, A>& item);
};
std::unordered_map<int, A> mp;
B b;
for (auto &pr : mp) {
	b.deal(pr);
}

在我的项目中A类管理了系统资源,我震惊地发现经过deal函数处理后A类所管理的资源会被释放(调用了析构函数)。这让我百思不得其解,我只是传递了一个引用而已啊,为什么会发生析构呢?经过调试发现在调用deal函数的时候发生了pair的拷贝操作,由于A类的拷贝构造是共享资源,所以在deal函数的参数pr析构的时候释放了资源。
那么问题就变成了为什么将mp的元素pr传递给deal就会发生拷贝?我们知道C++中普通引用要求两者的类型必须一致,而常量引用却可以发生类型转换,莫非是因为形参和实参的类型不一致?由于range循环的元素pr是推断出来的,那么的确有可能出现这种情况。接下来我们的问题就是搞清楚auto &pr是什么类型,然后修改deal的形参类型即可。(当然也可以将deal变成模板成员函数,然后用万能引用也可以解决问题)。
《Effective Morden C++》的条款4向我们介绍了如何查看型别推导的结果,有三种方法,分别是依赖IDE、依赖编译器诊断信息和在运行时输出。我使用的是Clion进行开发,还是很靠谱地显示了pr的类型为:std::pair<const int, A>&,而我们在类B中声明的形参为const std::pair<int, A>&,怪不得发生了拷贝构造。 于是我们修改B中的形参就可以啦。
如果IDE没有这么智能,那么还是可以依赖我们的好兄弟编译器的,《Effective Morden C++》中介绍了一种很trick的方法就是使用一个没有定义的模板类或者模板函数,只要我们试图使用这个模板,就会诱发一个错误信息,而编译器肯定会在错误信息中加上类型的名字。
于是我写了一个简单的测试函数:

template<typename T>
void printType(T t);

经过运行,编译器发出了错误警告:

undefined reference to `void edward::printType<std::pair<int const, edward::A> >(std::pair<int const, edward::A>)’

我也尝试了第三种看起来最优雅的运行时输出,书中喷了一下标准库的typeid的实现,推荐使用boost库中的boost::typeindex::type_id_with_cvr<T>().pretty_name()进行输出。但是我可能没有正确安装好boost库,导致找到这个函数。

总之,我们要千万小心mapunordered_map的元素类型为std::pair<const key_type, mapped_type>,如果忘记const可能会不小心产生拷贝操作,不仅仅会带来性能损耗,而且可能会产生RuntimeError。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是将上述代码转换为 Java 代码的示例: ```java import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Vector; public class PinTool { private static ADDRINT[] currentLocks = new ADDRINT[64]; // not all will be used and is to serve for programs with up to 64 worker threads. This is to catch real lock acquisitions private static Map<ADDRINT, Pair<List<Pair<THREADID, UINT32>>, Boolean>> memoryMap = new HashMap<>(); private static Map<ADDRINT, Pair<List<Pair<THREADID, UINT32>>, Boolean>> readMemoryMap = new HashMap<>(); private static Map<ADDRINT, Pair<List<Pair<THREADID, UINT32>>, Boolean>> lockMap = new HashMap<>(); private static Map<OS_THREAD_ID, THREADID> threadMap = new HashMap<>(); private static Map<THREADID, Pair<UINT32, UINT32>> threadAbstract = new HashMap<>(); public static void main(String[] args) { // Your code here } private static class Pair<F, S> { private F first; private S second; public Pair(F first, S second) { this.first = first; this.second = second; } public F getFirst() { return first; } public S getSecond() { return second; } public void setFirst(F first) { this.first = first; } public void setSecond(S second) { this.second = second; } } private static class ThreadID { // Your code here } } ``` 请注意,Java 中没有直接等价于 C++ 中的 `unordered_map` 和 `vector` 的类。因此,我们使用了 Java 的 `HashMap` 和 `List` 来实现相似的功能。我们还定义了一个 `Pair` 类来存储键值对,类似于 C++ 中的 `std::pair`。 在以上示例中,我们定义了与 C++ 代码中的变量相对应的 Java 变量,并在 `main` 方法中留出了代码的位置供你添加其他逻辑。你可以根据具体需求修改和扩展这段代码,以满足你的需求。 请注意,由于无法完全转换 C++ 中的数据结构和语法到 Java 中,因此你可能需要根据实际情况进行适当的调整和修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值