指针作为映射 C++ STL 中的键

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25122932/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 11:15:16  来源:igfitidea点击:

Pointers as keys in map C++ STL

c++pointersmapstl

提问by Ammar Husain

I have a question on how pointers to a custom object are handled when used as Keys in an map. More specifically if I define

我有一个问题,当在地图中用作键时,如何处理指向自定义对象的指针。更具体地说,如果我定义

std::map< CustomClass*, int > foo;

Would the default C++ implementation work to handle these pointers? Or do I need to define a custom comparator function to handle it? In general, is it good practice to use pointers to objects as keys?

默认的 C++ 实现可以处理这些指针吗?还是我需要定义一个自定义比较器函数来处理它?一般来说,使用指向对象的指针作为键是一种好习惯吗?

回答by Neil Kirk

The default implementation will compare the addresses stored by the pointers, so different objects will be considered as different keys. However, the logical state of the object will not be considered. For example, if you use std::string *as the key, two different std::stringobjects with the same text of "Hello"would be considered a different key! (When stored in the map by their addresses)

默认实现将比较指针存储的地址,因此不同的对象将被视为不同的键。但是,不会考虑对象的逻辑状态。例如,如果您将其std::string *用作键,则std::string具有相同文本的两个不同对象"Hello"将被视为不同的键!(当按他们的地址存储在地图中时)

It's ok to use pointers as keys so long as you understand the important difference above.

只要您理解上面的重要区别,就可以使用指针作为键。

回答by firda

Pointers will be handled but compared as pointers (memory order). You have to pass custom lessfunctor if you wish to compare the objects:

指针将被处理但作为指针进行比较(内存顺序)。less如果要比较对象,则必须传递自定义函子:

template<class T> struct ptr_less {
    bool operator()(T* lhs, T* rhs) {
        return *lhs < *rhs; }};
map<Object*,int,ptr_less<Object>> mymap;

回答by Wojtek Surowka

C++ standard provided specialisation of std::lessfor pointers, so yes you can safely use them as map keys etc.

C++ 标准提供了std::lessfor 指针的特化,所以是的,您可以安全地将它们用作映射键等。

回答by Steve Townsend

Leaving aside from the legality of this and any possible semantic misunderstandings, addressed already, I cannot think of any reason to use std::maphere rather than std::unordered_map. There are early intercepts of this in Boost and Visual C++ if you are on a pre-C++11 compiler.

撇开这个的合法性和任何可能的语义误解,已经解决了,我想不出有什么理由在std::map这里使用而不是std::unordered_map. 如果您使用的是 C++11 之前的编译器,那么在 Boost 和 Visual C++ 中会有早期拦截。

Since you appear to be using a pointer to represent a unique object, something like boost::flyweightcould be applicable.

由于您似乎使用指针来表示唯一对象,因此可能适用boost::flyweight 之类的内容

回答by blueskin

Pointers can be used as keys but especially with a std::map (or std::set) I would not advise it. The behavior of the program is not deterministic i.e. when one iterates over the map the order in which the items in the map are iterated is not guaranteed to be the same. It really depends on the memory address of the object (key). Take a look at this example, as you can see irrespective of the insertion order into the map the items are iterated in a deterministic way when the key is a string rather than a pointer.

指针可以用作键,但特别是对于 std::map(或 std::set),我不建议这样做。程序的行为不是确定性的,即当一个人在地图上迭代时,地图中项目的迭代顺序不能保证是相同的。它实际上取决于对象(键)的内存地址。看看这个例子,你可以看到,当键是一个字符串而不是一个指针时,无论映射中的插入顺序如何,项目都会以一种确定性的方式进行迭代。

http://ideone.com/VKirct

http://ideone.com/VKirct

#include <iostream>
#include <map>
using namespace std;

class SomeClass {
    public:
    SomeClass(const std::string& name): m_name(name) {}
    std::string GetName()const {return m_name; }
    bool operator <(const SomeClass& rhs) const { return m_name < rhs.m_name; }
    private:
    std::string m_name;
};

auto print_seq  = [](const auto& seq) { for (const auto& itr: seq) {std::cout << itr.second << " , ";} std::cout << std::endl;};

int main() {
    // your code goes here
    std::map<SomeClass*, std::string> pointer_keyed_map;
    SomeClass s3("object3");
    SomeClass s1("object1");
    SomeClass s2("object2");
    pointer_keyed_map.insert(std::make_pair(&s1, s1.GetName()));
    pointer_keyed_map.insert(std::make_pair(&s2, s2.GetName()));
    pointer_keyed_map.insert(std::make_pair(&s3, s3.GetName()));
    std::cout << "Pointer based keys: object order" << std::endl;
    print_seq(pointer_keyed_map);

    std::map<SomeClass, std::string> int_keyed_map;
    int_keyed_map.insert(std::make_pair(s3, s3.GetName()));
    int_keyed_map.insert(std::make_pair(s1, s1.GetName()));
    int_keyed_map.insert(std::make_pair(s2, s2.GetName()));
    std::cout << "String based keys: object order" << std::endl;
    print_seq(int_keyed_map);
    return 0;
}