实现带fill_range的strange_map:参数传递方式选型疑问
关于strange_map类fill_range函数参数传递的疑问
我正在实现一个strange_map类,它的fill_range函数可以将键的[a, b]范围全部赋值为指定值,核心代码如下:
template< class Key, class T, class Compare = std::less<Key>, class Allocator = std::allocator<std::pair<const Key, T>> > class strange_map { public: // 将[a, b]范围的键全部赋值为指定值 template <class KeyA, class KeyB, class U> void fill_range(KeyA&& a, KeyB&& b, U&& value) { // ... auto i = some_internal_map.find(a); // ... some_internal_map.emplace(std::forward<KeyA>(a), SomeInternalRange{ std::forward<KeyB>(b), std::forward<U>(value) }); // ... } private: struct SomeInternalRange { Key b; T value; }; std::map<Key, SomeInternalRange> some_internal_map; };
针对这个实现,我有以下疑问:
- 键和值参数应采用传值还是传引用的方式传递?
- 是否应该像示例中那样使用转发引用?
- 考虑到值总会被移动或复制,而键仅用于
some_internal_map.find(若范围已存在则不会插入),那么采用键用转发引用、值传值的方案(如下代码)是否合理?
template <class KeyA, class KeyB> void fill_range(KeyA&& a, KeyB&& b, T value);
使用示例
using StrangeMap = strange_map<int, std::string>; StrangeMap map; map.fill_range(1, 3, "a"); std::string b = "b"; map.fill_range(5, 7, b);
解答
1. 键与值参数的传递方式选择
- 键参数:优先考虑转发引用或
const Key&。如果需要支持可隐式转换为Key的类型(比如子类、兼容类型),转发引用更灵活,能避免不必要的拷贝;如果确定只会传入Key类型,const Key&也能满足需求,但转发引用的适配性更强。 - 值参数:推荐传值。因为最终要将值存储到内部结构中,传值允许调用方通过左值拷贝、右值移动的方式传递参数,结合移动语义,能减少拷贝次数。比如传入临时对象时,会直接移动构造函数参数,再移动到内部存储,仅需一次移动操作;而传
const T&则必须进行一次拷贝,效率更低。
2. 是否应该使用转发引用
对于键参数a和b,使用转发引用是合理的,原因如下:
- 支持任意可转换为
Key的类型,包括临时对象(右值)、左值,避免不必要的拷贝构造。 - 配合
std::forward可以完美转发参数到emplace等内部操作中,最大化效率。 - 注意:在调用
some_internal_map.find(a)时,如果a的类型不是Key,会隐式生成临时Key对象,此时可以提前构造一个Key变量(如Key key_a(std::forward<KeyA>(a));)再用于查找,避免临时对象的生命周期问题。
3. 键用转发引用、值传值的方案是否合理
这个方案非常合理,且是推荐的实现方式:
- 键用转发引用:保留了对各种键类型的兼容性,同时避免不必要的拷贝,适配左值、右值场景。
- 值传
T value:简化了模板参数(无需额外的U参数),同时利用移动语义将参数传递的开销降到最低。调用方传入左值时会拷贝构造value,再移动到内部结构;传入右值时则直接移动两次,开销远低于传引用再拷贝的方式。 - 完全匹配你的使用场景:值必然要被存储(所以最终需要拷贝/移动),键仅用于查找或插入,转发引用能覆盖所有可能的键传递场景。
内容的提问来源于stack exchange,提问作者Alexey Starinsky
相关产品推荐
相关产品推荐

