【发布时间】:2018-12-22 04:58:46
【问题描述】:
我有一个包含在std::shared_ptr 中的类,我想在std::priority_queue 的帮助下选择前k 个对象。所以,我定义operator < 并期望一切都会好起来的。但事实并非如此。默认情况下(使用 gcc)std::priority_queue 使用std::shared_ptr 的默认比较器,它比较地址。
但是,如果我将 std::sort 用于 std::vector 而没有指定比较器,则行为会有所不同,我的operator < 将被使用。这有点出乎意料和不一致的行为。
代码示例:
struct document
{
float rank;
document(float rank):
rank(rank)
{ }
};
using doc_ptr = shared_ptr<document>;
bool operator < (const doc_ptr& x, const doc_ptr& y)
{
return x->rank < y->rank;
}
int main()
{
priority_queue<doc_ptr> pq;
for(int i = 0; i < 10; i++) {
float r = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
pq.push(make_shared<document>(r));
}
vector<doc_ptr> pq_v;
while(!pq.empty()) {
cout << pq.top()->rank << " " << uint64_t(pq.top().get()) << endl;
pq.pop();
}
return 0;
}
我得到以下输出:
0.277775 35463848
0.76823 35463800
0.335223 35463752
0.197551 35463704
0.55397 35463560
0.911647 35463512
0.783099 35463384
0.79844 35463336
0.394383 35463288
0.840188 35463208
使用 clang(Apple LLVM 版本 9.1.0 (clang-902.0.39.2))一切正常。
std::priority_queue 和 std::sort 的完整代码用于std::vector:https://ideone.com/awsdrO
我想这可能与名称解析有关,但我自己无法找到它。所以,我想知道谁在这里,为什么?
UPD:这里的例子要简单得多:https://ideone.com/wm1YBw
最后一行输出在 gcc 和 clang 中有所不同,因为 gcc 为 shared_ptr 提供了 std::less 的特化,但 clang 没有。
【问题讨论】:
-
与您的问题无关,但要打印指针,您真的不应该将其转换为任何整数类型。 an
operator<<overload 接受void*并可用于任何指针。尤其如此,因为指针的大小不必是 64 位(尽管在大多数当前的 64 位系统上恰好是)。如果您真的需要一个指针大小的整数,请使用intptr_t(或uintptr_t)。 -
感谢您指出。实际上,我只是想将指针从十六进制转换为十进制,我认为它变得更具可读性(也许我错了)。
-
有趣的事实:
sort(v.begin(), v.end(), std::less<doc_ptr>());也按指针排序。所以这与通过std::less的间接性有关。但我不确定为什么。我的猜测是,这个特定的实现(我相信不正确)为shared_ptr提供了std::less的专业化。 -
@IgorTandetnik 你是对的。 gcc 为
shared_ptr提供了std::less的特化,但clang 没有。所以,我们现在可以有一个非常简单的例子:ideone.com/wm1YBw