通过EMPLEPE()将对象指针插入地图中

Insert an object pointer into a map of maps through emplace() does not work

本文关键字:指针 插入 地图 对象 EMPLEPE 通过      更新时间:2023-10-16

我正在尝试通过emplace()插入map的指针对象,但它不起作用。

我已经创建了以下问题的简单表示。我正在尝试插入newFooList指针对象类型Foo*

我似乎找不到在std::map<int, FooMap*> m_fooMapList中为FooMap*创建类型的方法。应该在地图的第二个字段上使用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;
}

on 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;

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

也就是说,FooMap的实例可以直接存在于地图本身中。

这样,您会获得更好的性能并避免记忆泄漏。

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

我不确定您是否需要一个地图结构,其中值是另一个地图的指针。FooMapList类可能很简单

std::map<int, FooMap> m_fooMapList;

另一方面,整个行指针的整个戏都只会给您带来痛苦。

以防万一 std::map<int, FooMap*> m_fooMapList;std::map<int, Foo*>是neccesarry,我会去智能pointers。

以下是一个示例代码,用std::unique_ptr替换行指针,并显示如何将Foo s的映射插入到映射。在这里看到Live

#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...

您可以丢弃您没有的地图类,停止使用指针,而只是

#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;
}

请注意,在此阶段,内图完全毫无意义,因为它们只有一个条目

除非您有一个很好的理由这样做,请避免使用这样的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_ptrstd::shared_ptr

我已经从每个答案中考虑了有效的点,以删除指针并删除无用的双层映射表示。但是,现实世界的抽象是一个非常复杂的问题,它涉及数千个需要动态创建和破坏的物体。使用指针似乎是一种有效的方法,但是Jejo的方法似乎更好。

我试图重新使用他的尝试,但使用对象指针,下面似乎有效。具有以下插入功能

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;
}

我也很感谢这种方法的反馈。我将将调用添加到destructor,以清理创建的对象