【发布时间】:2015-03-20 07:28:09
【问题描述】:
我将在热路径中使用 std::map 替换为 cpp-btree 的 btree_map。但是启用优化后,GCC 和 Clang 抱怨严格的别名违规。问题归结为:
template <typename Key, typename Value>
class btree_map {
public:
// In order to match the standard library's container interfaces
using value_type = std::pair<const Key, Value>;
private:
using mutable_value_type = std::pair<Key, Value>;
struct node_type {
mutable_value_type values[N];
// ...
};
public:
class iterator {
// ...
value_type& operator*() {
// Here we cast from const std::pair<Key, Value>&
// to const std::pair<const Key, Value>&
return reinterpret_cast<value_type&>(node->values[i]);
}
};
std::pair<iterator, bool> insert(const value_type& value) {
// ...
// At this point, we have to insert into the middle of a node.
// Here we rely on nodes containing mutable_value_type, because
// value_type isn't assignable due to the const Key member
std::move_backward(node->values + i, node->values + j,
node->values + j + 1);
node->values[i] = value;
// ...
}
};
这让我想到,有没有一种方法可以有效地做到这一点,而不依赖于未定义的行为?我使用的键可以有效地移动,但复制起来相当慢,所以我希望避免在每次插入时复制很多键。我考虑过
- 使用
value_type values[N],然后使用const_cast<Key&>(values[i].first) = std::move(key)来移动键,但我很确定它仍然未定义 - 适当时返回
std::pair<const Key&, Value&>而不是std::pair<const Key, Value>&,但我不确定这是否仍能满足容器要求(我听说...::reference应该是真正的引用类型) - 不在乎。代码按原样工作,但我很好奇它是否可以以符合标准的方式完成。未来的编译器也有可能对 UB 做不同的事情,我不知道有什么方法可以将
-fno-strict-aliasing仅应用于单个类。
还有其他想法吗?
【问题讨论】:
-
Gcc 提供may_alias attribute,这与 -fno-strict-aliasing 类似,但仅在涉及具有 may_alias 属性的特定变量的表达式中。
-
是的。 (你的意思是
may_alias对吗?)我想知道是否有办法在没有语言扩展的情况下做到这一点。 -
你必须使用 ad-hoc C-array 吗?你必须使用对象数组还是可以使用指针数组?
-
仅供参考,在boost::flat_map 中,他们将
value_type定义为typedef std::pair< Key, T > -
@frymode 好点。我很想在界面中保留
const Key的额外安全性,但可能不实用。
标签: c++ c++11 move undefined-behavior b-tree