所以问题是,当我尝试将非动态obj推送到playerList或者当我尝试删除n时,我得到段错(核心转储)。我假设问题是在Helper类被销毁时引起的,因此向量也被破坏,所以它试图破坏自身中不再存在的对象。但是,当我使用playerList.clear()时,问题仍然存在。我想我可以使用~Helper()来破坏playerList()中的对象。但我想知道为什么我不能使用非动态对象,只是在Run()结束时将它们从playerList中清除。
class Helper{
public:
void Run();
private:
std::vector<Player>playerList;
...
};
这是Run()的样子:
using namespace std;
void Helper::Run(){
Player *n = new Player();
playerList.push_back(*n); //Yup. There is a memleak
}
也 Player.h:
class Player{
public:
...
~Player();
private:
...
IClass* typeOfClass = new Warrior();
};
和~Player:
Player::~Player(){
delete typeOfClass;
}
和战士(对问题没有影响)
class Warrior {
public:
int GetMeleeAttack();
int GetRangedAttack();
int GetMagicAttack();
int AgilityAction();
int StrengthAction();
int IntelligenceAction();
void WhoAmI();
private:
};
Warrior的方法只返回一些整数。
答案 0 :(得分:1)
std::vector<Player>playerList;
应该是
std::vector<Player*>playerList;
如果要动态分配它们。另一种方法是放置每个元素,而不是使用new。
使用new时,您在堆上进行分配,但是您通过传递堆上分配的值来在向量中创建新元素。你有一个悬空指针(内存泄漏)
如果使用指针向量,请记住在解除向量时释放所有元素。
另一种方法是:
std::vector<std::unique_ptr<Player> >playerList;
这将解决分配问题。
答案 1 :(得分:0)
std::vector
的主要工作是为您动态分配对象,因此您无需使用new
和delete
。
void Helper::Run(){
playerList.push_back(Player());
}
这将默认构造一个新的玩家对象并将其添加到向量中。
答案 2 :(得分:0)
是的,可以通过存储指向Player
的指针来解决问题,但这会不必要地增加由于必须在IClass
内存储指针Player
而导致的问题。
相反,你可以通过制作
来消除整个问题IClass* typeOfClass;
进入
std::unique_ptr<IClass> typeOfClass;
或
std::shared_ptr<IClass> typeOfClass;
并使用
playerList.emplace_back();
Helper::Run
中的。
std::vector
会复制和销毁副本。为此,vector
包含的对象必须符合Rules of Three, Five, or Zero.
由于Player
拥有指针并使用默认复制功能,因此未遵守3/5/0要求的规则。因此,副本typeOfClass
指向与源typeOfClass
相同的位置。当源或副本被销毁时,它会删除源和副本正在使用的typeOfClass
,而另一个指向无效的内存。该程序现已破裂,可能会或可能不会崩溃。
但是如果Player
遵守规则并且有一个移动构造函数和一个移动赋值运算符,如下所示
class Player{
public:
...
~Player();
Player(Player && src)
{
typeOfClass = src.typeOfClass;
src.typeOfClass = nullptr;
}
Player& operator=(Player && src)
{
typeOfClass = src.typeOfClass;
src.typeOfClass = nullptr;
}
private:
...
IClass* typeOfClass = new Warrior();
};
然后vector
可以移动Players
,而不会让两个Player
共享相同的数据,Helper::Run
可能看起来像
void Helper::Run(){
playerList.emplace_back();
}
游戏中没有内存泄漏和更少的指针。
然而......你真正想要的是做尽可能少的特殊处理。每个特殊情况都意味着更多测试如果您可以在源头保护typeOfClass
,那么Player
可以作为帖子愚蠢并遵守零规则。
在这种情况下,这意味着使用像智能指针这样的代理对象来获取typeOfClass
的所有权并为您管理其生命周期。如果所有勇士都有Warrior
个实例,那就意味着std:shared_ptr
。如果勇士需要单独的Warrior
个实例来处理您想要Player
的{{1}}个实例的记账。