【问题标题】:C++ Memory Leaks with my std::map of &Objects and std::vector of &ObjectsC++ 内存泄漏与我的 &Objects 的 std::map 和 &Objects 的 std::vector
【发布时间】:2016-05-01 04:21:24
【问题描述】:

基本上我有这个

std::map<std::string, Location&> exits = std::map<std::string, Location&>();

作为类中的私有成员。而且我不确定当类的对象被删除时如何删除它以释放内存

我也有很多这样的向量

std::vector<Item> Ritems;

我也不确定如何删除,向量获取对象并添加到它

Deleaker 给了我大约 1000 个以下内容:

xmemory0,第 89 行(c:\program files (x86)\microsoft visual studio 14.0\vc\include\xmemory0)

位置对象

class Object;
class Location
{
    public:
        Location();
        Location(std::string RoomName, std::string RoomDesc);
        ~Location();
        Location(const Location& e);
        void AddExit(std::string Direction, Location &Room);
        void AddItem(Item &Items);
        void AddObject(Object &Objects);
        void RemoveObject(std::string ObjName);
        void AddNPC(NPC &NPCs);
        void PickUpItem(Character &CurChar, std::string ItemName);
        void DisplayAll();
        void DisplayExits();
        void DisplayItems();
        void DisplayObjects();
        void DisplayNPCs();
        std::string GetName();
        std::string GetDesc();
        Location GoCommand(std::string Direction);
        void TalkCommand(std::string Communication, Character &MainCharacter);
        Location operator=(const Location &other);
        Object CheckObject(std::string Command, std::string ObjName);
    private:
        std::string Name;
        std::string Description;

        std::map<std::string, Location&> exits = std::map<std::string, Location&>();

        std::vector<Item> Ritems;
        std::vector<Object> Robjects;
        std::vector<NPC> RNPC;
};

#include <iostream>
#include "Locations.h"  
#include <regex>
#include "Object.h"

Location::Location()
{
    Name = "";
    Description = "";
}
Location::Location(std::string RoomName, std::string RoomDesc)
{
    Name = RoomName;
    Description = RoomDesc;
}
Location::~Location()
{

}
Location::Location(const Location& e)
{
    Name = e.Name;
    Description = e.Description;
    exits = e.exits;
    Ritems = e.Ritems;
    Robjects = e.Robjects;
    RNPC = e.RNPC;
}
void Location::AddExit(std::string Direction, Location &Room)
{
    exits.insert(std::pair<std::string, Location*>(Direction, &Room));
}
void Location::AddItem(Item &Items)
{
    Ritems.push_back(Items);
}
void Location::AddObject(Object &Objects)
{
    Robjects.push_back(Objects);
}
void Location::RemoveObject(std::string ObjName)
{
    Object Temp;
    std::transform(ObjName.begin(), ObjName.end(), ObjName.begin(), ::tolower);
    for (int i = 0; i < Robjects.size(); i++)
    {
        std::string TempS = Robjects[i].GetName();
        std::transform(TempS.begin(), TempS.end(), TempS.begin(), ::tolower);
        if (TempS == ObjName)
            Robjects.erase(Robjects.begin() + i);
    }
}
void Location::AddNPC(NPC &NPCs)
{
    RNPC.push_back(NPCs);
}
void Location::PickUpItem(Character &CurChar, std::string ItemName)
{
    std::transform(ItemName.begin(), ItemName.end(), ItemName.begin(), ::tolower);

    for (int i = 0; i < Ritems.size(); i++)
    {
        std::string Temp = Ritems[i].GetName();
        std::transform(Temp.begin(), Temp.end(), Temp.begin(), ::tolower);
        if (Temp == ItemName)
        {
            CurChar.AddItem(Ritems[i]);
            Ritems.erase(Ritems.begin() + i);
        }
    }
}
Object Location::CheckObject(std::string Command, std::string ObjName)
{
    Object Temp;
    std::transform(Command.begin(), Command.end(), Command.begin(), ::tolower);
    std::transform(ObjName.begin(), ObjName.end(), ObjName.begin(), ::tolower);
    for (int i = 0; i < Robjects.size(); i++)
    {
        std::string TempS = Robjects[i].GetName();
        std::transform(TempS.begin(), TempS.end(), TempS.begin(), ::tolower);
        if (TempS == ObjName)
            return Robjects[i];
    }
    return Temp;
}
void Location::DisplayAll()
{
    WriteLine(7, '-');
    DisplayElement(7, Description);
    DisplayExits();
    DisplayItems();
    DisplayObjects();
    DisplayNPCs();
    WriteLine(7, '-');
}
void Location::DisplayExits()
{
    DisplayElement(7, "|- You can travel; ");

    for (std::map<std::string, Location*>::iterator ii = exits.begin(); ii != exits.end(); ++ii)
    {
        SetColour(7);
        std::cout << "\t";
        SetColour(112);
        std::cout << "[" << (*ii).first << "]";
        SetColour(8);
        std::cout << " to " << (*ii).second->GetName() << std::endl;
    }
}
void Location::DisplayItems()
{
    int Count = 0;
    if (Ritems.size() != 0)
    {
        DisplayElement(7, "Items in room: ");
        for (int i = 0; i < Ritems.size(); i++)
        {
            DisplayElementWC(Count, 5, 13, Ritems[i].GetName());
            DisplayElementWC(Count, 6, 14, Ritems[i].GetDesc());
            DisplayElementWC(Count, 6, 14, Ritems[i].GetItemValue());
            Count++;
        }
    }
}
void Location::DisplayObjects()
{
    int Count = 0;
    if (Robjects.size() != 0)
    {
        DisplayElement(7, "Objects in room: ");
        for (int i = 0; i < Robjects.size(); i++)
        {
            DisplayElementWC(Count, 5, 13, Robjects[i].GetName());
            DisplayElementWC(Count, 6, 14, Robjects[i].GetDesc());
        }
    }
}
void Location::DisplayNPCs()
{
    int Count = 0;
    if (RNPC.size() != 0)
    {
        DisplayElement(7, "NPCs in room: ");
        for (int i = 0; i < RNPC.size(); i++)
        {
            DisplayElementWC(Count, 5, 13, RNPC[i].GetName());
            DisplayElementWC(Count, 6, 14, RNPC[i].GetDesc());
        }
    }
}
std::string Location::GetName()
{
    return Name;
}
std::string Location::GetDesc()
{
    return Description;
}

Location Location::GoCommand(std::string Direction)
{
    Location ReturnLoc = *this;
    std::string Test;
    std::transform(Direction.begin(), Direction.end(), Direction.begin(), ::tolower);
    for (std::map<std::string, Location*>::iterator ii = exits.begin(); ii != exits.end(); ++ii)
    {
        Test = (*ii).first;
        std::transform(Test.begin(), Test.end(), Test.begin(), ::tolower);
        if (Test == Direction)
            ReturnLoc = *(*ii).second;
    }
    return ReturnLoc;
}
void Location::TalkCommand(std::string Communication, Character &MainCharacter)
{
    std::string Test;
    std::transform(Communication.begin(), Communication.end(), Communication.begin(), ::tolower);
    for (int i = 0; i < RNPC.size(); i++)
    {
        Test = RNPC[i].GetName();
        std::transform(Test.begin(), Test.end(), Test.begin(), ::tolower);
        if (Test == Communication)
        {
            RNPC[i].StartConvo(MainCharacter);
        }
    }
}
Location Location::operator=(const Location &other)
{
    Name = other.Name;
    Description = other.Description;
    exits = other.exits;
    Ritems = other.Ritems;
    Robjects = other.Robjects;
    RNPC = other.RNPC;
    return *this;
}

好吧,我希望这是一个 MCVE 啊哈

#include <iostream>
#include <map>
#include <regex>
#include <string>
#include <windows.h>
#include <cctype>
//Custom Classes

class Location;
class UpdateLocation
{
public:
    UpdateLocation();
    ~UpdateLocation();
    void AddLocation(Location &Room);
    void UpdateNow(Location &Room);
    Location GetLocal(Location &Room);

private:
    std::map<std::string, Location*> Locations = std::map<std::string, Location*>();
};

class Location
{
public:
    Location();
    Location(std::string RoomName, std::string RoomDesc);
    ~Location();
    Location(const Location& e);
    void AddExit(std::string Direction, Location &Room);
    void DisplayExits();
    std::string GetName();
    std::string GetDesc();
    Location operator=(const Location &other);
private:
    std::string Name;
    std::string Description;

    std::map<std::string, Location*> exits = std::map<std::string, Location*>();
};

UpdateLocation::UpdateLocation()
{

}
UpdateLocation::~UpdateLocation()
{

}
void UpdateLocation::AddLocation(Location &Room)
{
    Locations.insert(std::pair<std::string, Location*>(Room.GetName(), &Room));
}
void UpdateLocation::UpdateNow(Location &Room)
{
    for (std::map<std::string, Location*>::iterator ii = Locations.begin(); ii != Locations.end(); ++ii)
    {
        if ((*ii).first == Room.GetName())
        {
            *(*ii).second = Room;
        }
    }
}
Location UpdateLocation::GetLocal(Location &Room)
{
    for (std::map<std::string, Location*>::iterator ii = Locations.begin(); ii != Locations.end(); ++ii)
    {
        if ((*ii).first == Room.GetName())
        {
            return *(*ii).second;
        }
    }
}

Location::Location()
{
    Name = "";
    Description = "";
}
Location::Location(std::string RoomName, std::string RoomDesc)
{
    Name = RoomName;
    Description = RoomDesc;
}
Location::~Location()
{

}
Location::Location(const Location& e)
{
    Name = e.Name;
    Description = e.Description;
    exits = e.exits;

}
void Location::AddExit(std::string Direction, Location &Room)
{
    exits.insert(std::pair<std::string, Location*>(Direction, &Room));
}
void Location::DisplayExits()
{
    std::cout << "|- You can travel; " << std::endl;

    for (std::map<std::string, Location*>::iterator ii = exits.begin(); ii != exits.end(); ++ii)
    {
        std::cout << "\t";
        std::cout << "[" << (*ii).first << "]";
        std::cout << " to " << (*ii).second->GetName() << std::endl;
    }
}
std::string Location::GetName()
{
    return Name;
}
std::string Location::GetDesc()
{
    return Description;
}
Location Location::operator=(const Location &other)
{
    Name = other.Name;
    Description = other.Description;
    exits = other.exits;
    return *this;
}

void main()
{
    //Create GameWorld
    UpdateLocation UpdateIt;
    Location HallWay("Hallway", "Long corridor with a wide array of footboats");

    getchar();
    getchar();
}

【问题讨论】:

  • 你不要删除这些内存。
  • 我不明白所有 1000 次泄漏可能来自哪里?
  • 你在Item中分配内存吗?也许你没有正确处理 3 的规则。
  • 所有项目只有几个字符串和布尔值
  • 您只能使用delete 使用new 创建的东西。除非您使用new 创建容器,否则您不会删除它们,并且您不会删除容器的元素,除非您使用new 创建它们。也就是说,您的设计暗示了对对象所有权的一些混淆,应该进行更改以使所有权清晰明确。此外,您的 MCVE 不会显示任何泄漏,因为它没有做任何事情。你永远不会向容器中添加任何东西。您忘记了实际演示问题的 MCVE 部分。

标签: c++ object dictionary memory reference


【解决方案1】:

首先,您可能想阅读以下内容(对于 c++03 及更早版本):

Why Can't I store references in an STL map in C++?

对于 c++11 及更高版本,实际上可以使用 std::map::emplace() 将引用作为 std::maps 中的值,但这很不方便,我看不出它与原始指针一样有用,也应该用 @ 替换987654324@s 如果容器对象拥有放置在其中的对象。

你可能想要

std::map<std::string, Location *> exits;

作为您的私人会员。无需删除您的地图或矢量。当你的类的析构函数被调用时,相应对象的析构函数就会被调用。他们基本上是自毁的。您解释了exits 对象不拥有Location 对象,因此exits 不应该与释放分配给它们的内存有任何关系。

【讨论】:

  • 这不起作用,因为当我将位置移动到另一个位置时,数据不在那里,我已将位置定义添加到我的原始帖子中
  • 然后检查Location::Location(const Location &amp;) 和Location Location::operator=(const Location &amp;) 的实现。或者尝试删除它们,看看默认的有什么作用......
  • exits成员变量的作用是什么?
  • 嗯,这些位置是通过一个方向连接起来的,你向下“移动”到其他位置。 exits 成员变量存储另一个位置的位置。
  • 我想我明白了。每个Location 都让Locations 与其相邻。为了让它工作,如果你可以确定在删除单个Location 对象后不使用exits 中的值,我建议使用原始指针:std::map&lt;std::string, Location *&gt;。如果您在使用std::map 访问时遇到速度问题,您可能希望将enum 与std::array 结合使用,但如果没有实际测量,那将是过早的优化。原始指针也可以稍后替换为 std::shared_ptr 以使其更加健壮。
猜你喜欢
  • 2014-08-18
  • 2017-02-19
  • 1970-01-01
  • 1970-01-01
  • 2011-10-02
  • 1970-01-01
  • 2010-11-25
  • 1970-01-01
  • 2016-02-07
相关资源
最近更新 更多