c – 是否有任何理由不使用异常来测试std :: map中是否存在元素
我最近开始在许多项目中使用c 11,并且还开始大量使用我相对较新的stl容器.
我有一个我最近写的函数,它做了类似的事情: CMyClass* CreateAndOrGetClass( int _iObjectId,std::map<int,CMyClass*>& _mapObjectData ) { CMyClass* pClassInstance{ nullptr }; try { pClassInstance = _mapObjectData.at( _iObjectId); } catch ( ... ) { pClassInstance = new CMyClass(); __mapObjectData.insert( _iObjectId,pClassInstance ); } return ( pClassInstance ); } 我的问题是关于明显不是“特殊”条件的例外情况.它似乎是实现手头目的的一种非常简洁的方式,而不是涉及设置迭代器. 对于我可能会遗漏的此类目的使用异常是否有任何问题? 测量* 因此,为了跟进,我做了一些性能测试,将基于异常的代码与所选答案中的代码示例进行比较.通过使用正常代码流的异常来验证不良性能的建议是一个很好的练习.它还提供了一些很好的参考资料,用于在不抛出异常时断言接近于零的性能损失. 虽然这些测试并非详尽无遗,但我观察到的是: 每个测试都使用rand()作为映射键的源(生成最大32768个元素)在大量插入/提取上运行: 例外方法:平均5.99秒 将随机元素的范围扩大十倍可以得到这些数字: 例外方法:平均56.7秒 然后我用所有可能的密钥条目预填充地图,以便尝试从不抛出: 例外方法:平均0.162秒 奇怪的是,使用MS VStudio,异常处理方法的调试模式代码更快. 解决方法
例外是将故障处理与正常案例代码完全分开的一种方法.
在你的代码中,它们被用于正常情况,这会破坏目的而没有任何优势. 在特定情况下,使用[]索引,如果密钥已经存在则会自动插入密钥.更常见的是使用条件结构来实现简单的条件控制流程.在某些特殊情况下,异常对于表达正常的案例控制流是有意义的(例如,从深度嵌套的递归调用返回结果),在某种意义上代码可以变得更简单和更清晰,但是这些例外情况是……例外. 关于效率,抛出异常是昂贵的,因为C编译器针对故障处理使用异常进行了优化,这被认为是罕见的. 当失败成为常态时,重新考虑失败的工作定义. 但是,只是抛出异常的可能性很小,低至0,开销.因此,您不应该害怕使用异常来安全地处理失败,并且不会分散注意力,使其远离正常的案例代码.正确使用,将这种代码划分为正常情况和失败,例外是双赢的. 在a comment到另一个回答你说,
那是一种失败的情况,使用异常处理是正确的方法. 例如, Your_class* creative_at( int const id,YourClass*>& object_data ) { // Basic non-creating at: { auto const it = object_data.find( id ); if( it != object_data.end() ) { return it->second; } } // Create: std::unique_ptr<Your_class> p( new Your_class() ); // May throw. object_data[id] = p.get(); // May throw. return p.release(); } 此代码基于异常,但看不到尝试捕获. 在C语言中,主要是让析构函数进行自动清理,例如在本例中为std :: unique_ptr析构函数,而不是Java方法的try-catch-finally.这种方法称为RAII,是资源获取初始化的缩写. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |