代码之家  ›  专栏  ›  技术社区  ›  Inian

通过emplace()将对象指针插入映射的映射中不起作用

  •  0
  • Inian  · 技术社区  · 6 年前

    我试图插入一个指针对象到 map 通过 emplace() 但它不起作用。

    我已经为下面的问题创建了一个简单的表示。我想插入到 newFooList 指针对象类型 Foo* .

    我似乎找不到创建 FooMap* 在里面 std::map<int, FooMap*> m_fooMapList . 是不是应该用 new 在地图的第二个区域?

    #include <iostream>
    #include <utility>
    #include <stdint.h>
    #include <cstdlib>
    #include <map>
    
    class Foo
    {
        private:
            int m_foobar;
        public:
            Foo(int value)
            {
                m_foobar = value;
            }
            void setfoobar(int value);
            int getfoobar();
    };
    
    class FooMap
    {
        private:
            std::map<int, Foo*> m_newFoo;
    
        public:
            FooMap() = default;
    };
    
    class FooMapList
    {
        private:
            std::map<int, FooMap*> m_fooMapList;
        public:
            FooMapList() = default;
            void insertFoo(Foo* newFooObj);
    };
    
    int Foo::getfoobar(void)
    {
        return(m_foobar);
    }
    
    void FooMapList::insertFoo(Foo* newFooObj)
    {
        if(m_fooMapList.empty())
        {
            std::cout << "m_fooMapList is empty" << std::endl ;
        }
    
        //m_fooMapList.emplace( newFooObj->getfoobar(), newFooObj  );
        // Need to find a way to insert newFooObj  to m_fooMapList
        m_fooMapList.second = new FooMap;
    }
    
    int main() {
        FooMapList newFooList;
    
        for (auto i=1; i<=5; i++)
        {
            Foo *newFoo = new Foo(i);
            newFoo->getfoobar();
            newFooList.insertFoo(newFoo);
        }
    
        return 0;
    }
    

    在g++上(GCC)4.8.5 20150623(红帽4.8.5-28)

    $  g++ -std=c++11 -Wall map_of_map.cpp 
    map_of_map.cpp: In member function ‘void FooMapList::insertFoo(Foo*)’:
    map_of_map.cpp:51:18: error: ‘class std::map<int, FooMap*>’ has no member named ‘second’
         m_fooMapList.second = new FooMap;
    
    1 回复  |  直到 6 年前
        1
  •  3
  •   JeJo    6 年前

    我不确定您是否需要一个映射结构,其中的值是指向另一个映射的指针。这个 FooMapList 课程可能很简单

    std::map<int, FooMap> m_fooMapList;
    

    另一方面,整个与行指针的游戏只会给你带来脖子上的疼痛。

    如果使用 std::map<int, FooMap*> m_fooMapList; std::map<int, Foo*> 有必要的话,我会选聪明人。

    下面是用替换行指针的示例代码 std::unique_ptr 并演示如何插入 地图 Foo s至 地图 到位。 See live here

    #include <iostream>
    #include <utility>
    #include <map>
    #include <memory>
    
    class Foo
    {
    private:
        int m_foobar;
    public:
        Foo(int value): m_foobar(value) {}
        void setfoobar(int value) noexcept { m_foobar = value; }
        int getfoobar() const noexcept { return m_foobar; }
    };
    
    class FooMap
    {
    private:
        std::map<int, std::unique_ptr<Foo>> m_newFoo;
        //            ^^^^^^^^^^^^^^^^^^^^
    public:
        FooMap() = default;
    #if 0 // optional
        // copy disabled
        FooMap(const FooMap&) = delete;
        FooMap& operator=(const FooMap&) = delete;
    
        // move enabled
        FooMap(FooMap&&) = default;
        FooMap& operator=(FooMap&&) = default;
    #endif
        // provide a helper function to insert new Foo to the map of Foo s
        void insertFoo(std::unique_ptr<Foo> newFooObj)
        //             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        {
            std::cout << "inserting to FooMap..." << std::endl;
            m_newFoo.emplace(newFooObj->getfoobar(), std::move(newFooObj)); // construct in place
        }
    };
    
    class FooMapList
    {
    private:
        std::map<int, std::unique_ptr<FooMap>> m_fooMapList;
        //            ^^^^^^^^^^^^^^^^^^^^^^^
    public:
        FooMapList() = default;
    
        void insertFooMap(std::unique_ptr<Foo> newFooObj)
        //               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        {
            if (m_fooMapList.empty())
            {
                std::cout << "m_fooMapList is empty" << std::endl;
            }
            // create FooMap and insert Foo to it.
            FooMap fooMap;
            const auto key = newFooObj->getfoobar();
            fooMap.insertFoo(std::move(newFooObj));
    
            // finally insert the FooMap to m_fooMapList
            std::cout << "inserting to fooMapList..." << std::endl;
            m_fooMapList.emplace(key, std::make_unique<FooMap>(std::move(fooMap))); // construct in place
        }
    };
    
    int main() 
    {
        FooMapList newFooList;
    
        for (auto i = 1; i <= 5; i++)
        {
            auto newFoo = std::make_unique<Foo>(i);
            std::cout << newFoo->getfoobar() << std::endl;
            newFooList.insertFooMap(std::move(newFoo));
        }
    
        return 0;
    }
    

    输出 :

    1
    m_fooMapList is empty
    inserting to FooMap...
    inserting to fooMapList...
    2
    inserting to FooMap...
    inserting to fooMapList...
    3
    inserting to FooMap...
    inserting to fooMapList...
    4
    inserting to FooMap...
    inserting to fooMapList...
    5
    inserting to FooMap...
    inserting to fooMapList...
    
        2
  •  5
  •   rustyx    6 年前

    m_fooMapList 定义为

        std::map<int, FooMap*> m_fooMapList;
    

    所以要插入它,你需要一个 int 以及指向 FooMap :

        m_fooMapList.emplace(newFooObj->getfoobar(), new FooMap);
    

    话虽如此,您应该使用C++值语义,而不依赖于原始指针:

        std::map<int, FooMap> m_fooMapList; // no pointers
    
        m_fooMapList.emplace(newFooObj->getfoobar(), {}); // construct objects in-place
    

    也就是说 食物地图 可以直接位于地图本身。

    这样可以获得更好的性能并避免内存泄漏。

    也值得研究智能指针(例如。 unique_ptr )如果你真的想使用指针。

        3
  •  2
  •   Caleth    6 年前

    你可以扔掉你的什么都不做的映射类,停止使用指针,然后

    #include <iostream>
    #include <utility>
    #include <stdint.h>
    #include <cstdlib>
    #include <map>
    
    class Foo
    {
    private:
        int m_foobar;
    public:
        Foo(int value) : m_foobar(value) { }
        void setfoobar(int value) { m_foobar = value; }
        int getfoobar() const { return m_foobar; }
    
        // or more simply
        // int foobar;
    };
    
    using FooMap = std::map<int, Foo>;
    
    using FooMapMap = std::map<int, FooMap>;
    
    int main() {
        FooMapMap foos;
    
        for (auto i=1; i<=5; i++)
        {
            foos[i][i] = Foo(i);
        }
    
        return 0;
    }
    

    注意内部地图是 完全没有意义 在这个阶段,因为他们只有一个入口

        4
  •  1
  •   Rerito    6 年前

    除非你有一个很好的理由这么做,否则避免像这样混淆la-Java的东西,并尽可能利用STL。为此,可以使用类型别名

    using FooMap = std::map<int, Foo*>; // Maybe use a smart pointer instead here?
    using FooMapList = std::map<int, FooMap>; // Maybe List is not an appropriate name for a map
    

    现在,你有一个 Foo 元素,您刚刚创建并希望将其插入到地图列表中,为此,您需要一种方法来选择要在列表中插入的地图。我假设您将在列表中的第一张地图中插入:

    auto FooMap::emplace(int key, Foo* value)
    {
        return m_newFoo.emplace(key, value);
    }
    
    void FooMapList::insertFoo(Foo* newFooObj)
    {
        // If the map for `getfoobar` does not exist yet, operator[] will create it
        auto& mapPtr = m_fooMapList[newFooObj->getfoobar()];
        if (nullptr == mapPtr)
            mapPtr = new FooMap();
    
        mapPtr->emplace(
            newFooObj->getfoobar(),
            newFooObj
        );
    }
    

    注意,我没有处理内存清理。我建议你尽量使用智能指针( std::unique_ptr std::shared_ptr )

        5
  •  0
  •   Inian    6 年前

    我考虑了每个答案中的有效点,以删除指针并删除无用的双层映射表示。但是,现实世界的抽象是一个非常复杂的问题,它涉及到成千上万的动态对象,需要动态地创建和销毁这些对象。使用指针似乎是一种有效的方法,但是 JeJo' approach 看起来好多了。

    我试图重新使用他的尝试,但对象指针和下面的似乎工作。具有以下插入函数

    FooMap 函数将是

    void FooMap::insertFoo(Foo* newFooObj)
    {
        m_newFoo.emplace(newFooObj->getfoobar(), newFooObj);
    }
    
    const std::map<int, Foo*> FooMap::getList()
    {
        return m_newFoo;
    }
    

    FooMapList 可能是

    void FooMapList::insertFooList(Foo* newFooObj)
    {
        std::map <int, FooMap*>::iterator iter;
        FooMap *localFooMap = NULL;
        iter = m_fooMapList.find( newFooObj->getfoobar() );
    
        if( iter == m_fooMapList.end() )
        {
            localFooMap = new FooMap;
            localFooMap->insertFoo(newFooObj);
            m_fooMapList.emplace(newFooObj->getfoobar(), localFooMap );
        }
        else
        {    
            localFooMap = iter->second;
            localFooMap->insertFoo(newFooObj);
            m_fooMapList.emplace(newFooObj->getfoobar(), localFooMap );
        }
    }
    
    const std::map<int, FooMap*> FooMapList::getList()
    {
        return m_fooMapList;
    }
    

    我也希望能得到这种方法的反馈。我将添加对析构函数的调用来清理创建的对象