【发布时间】:2021-11-29 13:29:30
【问题描述】:
我写了一个这样的Edge 类:
struct Edge : public ::std::pair<int, int>
{
using ::std::pair<int, int>::pair;
int &src = first;
int &dst = second;
};
namespace std
{
template <>
struct hash<Edge>
{
std::size_t operator()(Edge const &x) const noexcept
{
return (x.src << 16) | x.dst;
}
};
}
所以我可以用src/dst 代替first/second。
但是,当我使用std::unordered_set 时,我发现出了问题。
Edge e(1, 2);
print_edge_debug_info(e);
using _set_t = std::unordered_set<Edge>;
_set_t s;
s.insert(e);
for(auto &&_e : s) {
print_edge_debug_info(_e);
}
/*
output:
(1, 2) [ 2,0x7ffca1c08724] [ 2,0x7ffca1c08724]
(1, 2) [ 2,0x2bb80fc] [ 2,0x7ffca1c08724]
*/
print_edge_debug_info:
inline void print_edge_debug_info(Edge const &edge)
{
std::cout << edge
<< " "
<< "[ " << edge.second << "," << &edge.second << "] "
<< " "
<< "[ " << edge.dst << "," << &edge.dst << "] "
<< std::endl;
}
dst 和 second 在构造第一个 Edge 对象后具有相同的地址。但是如果我把这个Edge 对象放到std::unordered_set 中并从集合中取出,结果的dst 和second 的地址是不同的。
此外,新的second 和旧的second 有不同的地址。但是新的dst 和旧的dst 具有相同的地址。这意味着新的dst 是旧second 的别名,而不是新second 的别名。
这对我来说似乎很奇怪。我不明白为什么会这样。
我使成员别名的方式错误吗?正确的方法是什么?
【问题讨论】:
-
引用成员不是普通别名。它们是在复制、分配或移动时必须考虑的适当成员。添加对混合的引用会使the rule of 3 违规更加突出,我怀疑这里就是这种情况。为什么不直接使用成员函数访问器呢?它会为您省去很多麻烦。
-
@StoryTeller-UnslanderMonica 实际上,我昨天已经将它们更改为 getter/setter。我只是好奇我的代码发生了什么。所以我把我的旧代码(即上面的代码)写了一个简单的版本并研究它。
-
为什么要继承
std::pair?据我所知,写struct Edge {int src; int dst;};完全符合您的要求。