我在一些代码中添加了一个析构函数,它似乎在尽早调用并引起问题。我添加了一条调试语句以查看它的调用位置,这使我更加困惑。我了解管理自己的记忆不是最佳做法,但我想亲自尝试一下。
这基本上是我的GameObject类:
class min
{
public static void Main(string[] args)
{
min p = new min();
}
public min()
{
DetailsMenu(1);
}
List<string> active = new List<string>() { "Example1", "Example2", "Example3" };
string input = "";
int index;
/// <summary>
/// Creates a detail menu
/// </summary>
/// <param name="index">What name</param>
public void DetailsMenu(int index)
{
Console.CursorVisible = false;
this.index = index;
Thread Input = new Thread(new ThreadStart(DetailMenuInput));
Thread Details = new Thread(new ThreadStart(DetailsMenuThread));
Input.Start();
Details.Start();
}
/// <summary>
/// Displays the screen it self
/// </summary>
void DetailsMenuThread()
{
while (true)
{
Console.Clear();
Console.WriteLine($"{active[index - 1]}");
Console.SetCursorPosition(0, Console.WindowHeight - 1);
Console.WriteLine($">{input}_");
Console.SetWindowPosition(0, 0);
Thread.Sleep(100);
}
}
/// <summary>
/// Needs to handle input
/// in this function i need to press a key twice to add it to input
/// </summary>
void DetailMenuInput()
{
while (true)
{
Console.TreatControlCAsInput = false;
var key = Console.ReadKey(true);
if (key.Key == ConsoleKey.Backspace)
{
if (input.Length > 0)
input = input.Remove(input.Length - 1);
continue;
}
input += Console.ReadKey(true).KeyChar.ToString();
}
}
}
这是createPlayer方法:
class GameObject
{
public:
int xCoord = 0, yCoord = 0, prevX, prevY;
int status = 0, weight = -1;
int id = -1;
GameObject(CommandComponent* commands,
PhysicsComponent* physics,
GraphicsComponent* graphics)
: commandComponent(commands),
physicsComponent(physics),
graphicsComponent(graphics)
{};
~GameObject()
{
std::cout << "Destructor called " << id << std::endl;
delete commandComponent;
delete physicsComponent;
delete graphicsComponent;
};
void update(World& world, int command, sf::Time dt)
{
commandComponent->update(*this, world, command);
physicsComponent->update(*this, world);
graphicsComponent->update(*this, dt);
};
void update(World& world, int command)
{
commandComponent->update(*this, world, command);
physicsComponent->update(*this, world);
};
sf::Sprite draw()
{
return *(graphicsComponent->draw());
};
void setCoords(int x, int y)
{
prevX = xCoord;
xCoord = x;
prevY = yCoord;
yCoord = y;
};
void setId(int newId)
{
id = newId;
}
private:
CommandComponent* commandComponent = NULL;
GraphicsComponent* graphicsComponent = NULL;
PhysicsComponent* physicsComponent = NULL;
};
我调用此方法将新对象添加到向量,基于它是活动对象还是非活动对象,我还将其添加到数组:
GameObject* createPlayer(sf::Texture* text)
{
return new GameObject(new PlayerCommandComponent(), new PlayerPhysicsComponent(), new PlayerGraphicsComponent(text));
};
最后,这是我的测试代码,该代码创建游戏对象并调用上面的函数,在此我看到从以下位置调用析构函数:
void World::addObject(GameObject object, int id, int type){
object.setId(id);
if (type == 0)
{
inactiveObjects.push_back(object);
}
else if (type == 1)
{
activeObjects.push_back(object);
}
}
我想我的主要问题是如何调用Destructors?我假设它与我在createPlayer方法中构造对象的方式有关,也许在返回它后它就超出范围了,但是我认为使用new关键字可以防止这种情况的发生?我在这里感到困惑。
答案 0 :(得分:2)
这里有几件事在起作用。
GameObject* createPlayer(sf::Texture* text)
返回动态分配的GameObject
。 This could be done better,继续阅读std::unique_ptr
,但这里没有严格的错误。我主要是为了指出std::unique_ptr
并进行设置
addObject((*createPlayer(&(mTextures.get(Textures::PlayerCharacter)))), 0, 1);
因为这是开始出错的地方。当您找到使用new
并取消引用并丢弃结果的代码时,您正在查看的是内存泄漏。您已经失去了指向动态分配对象的指针,并且没有了指针,几乎不可能再次找到分配,因此可以delete
。
存储解引用的对象将调用复制构造函数或赋值运算符,此时,您需要考虑The Rule of Three:如果需要使用a来定义自定义析构函数,则可能需要定义一个自定义赋值运算符和副本构造函数。这是何时需要观察Rule of Three的标准示例。在Rule of Three链接中可以清楚地解释问题所在,因此请先停止阅读并了解它,然后再继续进行操作。否则,此答案的其余部分将对您几乎无用。
如果不牢牢把握the Rule of Three and all of its friends,就不能编写出色的C ++代码。
您可以通过更改
来绕过三规则void World::addObject(GameObject object, int id, int type)
到
void World::addObject(GameObject * object, int id, int type)
,并通过引用传递object
。这没什么帮助,因为
inactiveObjects.push_back(object);
期望一个对象,而不是指针。
您也可以更改它,但是应该吗? std::vector
在直接包含对象时处于绝对最佳状态。指针导致指针追逐,不良的缓存行为,最终导致suuuhhhfering。除非您有充分的理由,否则不要存储指针。
如果这样做,则以std::unique_ptr
开始到结束来管理指针。
直接跳过三个规则,然后转到The Rule of Five。
commandComponent
,physicsComponent
(或其中)和graphicsComponent
。GameObject
以及CommandComponent
,PhysicsComponent
和GraphicsComponent
添加移动构造函数并将赋值运算符移动到GraphicsComponent
。使所有资源管理尽可能靠近资源。这使您可以使更高级别的类尽可能地无知。如果GameObject
知道如何复制和移动自己,则GameObject
不需要知道如何移动它。这使您可以利用The Rule of Zero的优势,零规则应该是您在所有课程中都追求的目标。GameObject*
到createPlayer
和activeObjects
inactiveObjects
的{{1}},而不是vector
。 / li>