指针的意外行为(操作时)但使用双指针时定义的行为
Unexpected behaviour by pointer (when manipulated) but defined behaviour when using a double pointer
我对指向变量的指针行为背后的推理感到很困惑。我本以为,如果我将一个指针附加到 vector
并访问它,无论我是否更改了指针本身,它仍然应该对同一个变量起作用。我的意思是,例如,我有一个整数指针向量,我修改了一个在别处定义的变量,该变量已附加到向量中。如果我要打印它们,它应该更新向量(实际上不是)但它应该打印一个整数的新值。我正在尝试将其应用于 SDL2 中的 SDL_Texture*
,但它并没有多大意义。总之,相同的概念也适用于此,但我使用的是纹理。我修改了纹理并用它做“事情”,但是在渲染它的循环结束时,向量仍然迭代到附加到它的 SDL_Texture*
。我的问题是,当我更改和修改纹理时,当我去渲染它时它没有显示出来。这不是因为纹理没有正确加载或任何东西(我已经测试过它并且没有使用矢量,而是原始绘制它)但是当使用矢量时它不能正常工作。这是代码:
void Main::Mainloop()
{
Screen_Object m_Screen_Object;
TTF_Font* font = TTF_OpenFont("Anonymous_Pro.ttf", 30);
SDL_Surface* surf = TTF_RenderText_Blended(font, "Starting fps", {0,0,0});
SDL_Texture* tex = SDL_CreateTextureFromSurface(Render::Get_Renderer(), surf);
SDL_FreeSurface(surf);
SDL_Rect rct = {20, 100, 0,0};
SDL_QueryTexture(tex, NULL, NULL, &rct.w, &rct.h);
m_Screen_Object.Add_Texture(tex);
Uint32 start, finish, counter;
counter = 0;
start = SDL_GetTicks();
finish = SDL_GetTicks();
bool running = true;
while (running)
{
Events::Event_Loop();
if (Events::Quit_Application()){
running = false;
break;
}
///Clear display to color
SDL_SetRenderDrawColor(Render::Get_Renderer(), 0,255,0,255);
SDL_RenderClear(Render::Get_Renderer());
///Do stuff here
m_Screen_Object.Draw_Textures();
finish = SDL_GetTicks();
counter += 2;
if (finish - start >= 500)
{
start = SDL_GetTicks();
SDL_DestroyTexture(tex);
std::string fps = std::to_string(counter);
surf = TTF_RenderText_Blended(font, fps.c_str(), {0,0,0});
tex = SDL_CreateTextureFromSurface(Render::Get_Renderer(), surf);
SDL_FreeSurface(surf);
SDL_QueryTexture(tex, NULL, NULL, &rct.w, &rct.h);
counter = 0;
}
SDL_RenderPresent(Render::Get_Renderer());
}
SDL_DestroyTexture(tex);
TTF_CloseFont(font);
}
int main(int argc, char* argv[])
{
Main::Mainloop();
return 0;
}
这里是 Screen_Object
的声明:
在header:
std::vector < SDL_Texture* > m_Textures;
在.cpp中:
void Screen_Object::Add_Texture(SDL_Texture* p_Texture)
{
m_Textures.push_back(p_Texture);
}
void Screen_Object::Draw_Textures()
{
for (unsigned int i=0; i < m_Textures.size(); i++)
{
SDL_RenderCopy(Render::Get_Renderer(), m_Textures[i], NULL, &m_Rect);
}
}
现在这段代码没有按照我认为应该的方式工作,因为我不明白为什么它不工作,但是当我将向量的类型更改为 SDL_Texture**
时,代码可以工作美好的。没有**
的代码到底有什么问题,我无法从逻辑上理解为什么它不能正常工作
问题似乎是您在向量中存储指针,但在向量外部您使指针无效。
void Screen_Object::Add_Texture(SDL_Texture* p_Texture)
{
m_Textures.push_back(p_Texture);
}
void Main::Mainloop()
{
Screen_Object m_Screen_Object;
//...
SDL_Texture* tex = SDL_CreateTextureFromSurface(Render::Get_Renderer(), surf);
//...
m_Screen_Object.Add_Texture(tex); // <-- add pointer to vector
//...
tex = SDL_CreateTextureFromSurface(Render::Get_Renderer(), surf); // <-- This changes the pointer, but has no effect on the vector's
//...
所以在该行之后的任何内容,如果您访问 m_Textures
向量中的指针,向量中的指针将不再有效,或者更糟的是,它是有效的,但指向一个旧的(但仍然有效) SDL_Texture
.
一个非常简单的解决方案是通过获取对该指针的引用来确保您使用存储在 m_Textures
中的指针:
void Main::Mainloop()
{
Screen_Object m_Screen_Object;
TTF_Font* font = TTF_OpenFont("Anonymous_Pro.ttf", 30);
SDL_Surface* surf = TTF_RenderText_Blended(font, "Starting fps", {0,0,0});
SDL_Texture* tex = SDL_CreateTextureFromSurface(Render::Get_Renderer(), surf);
m_Screen_Object.Add_Texture(tex); // <-- Immediately do this
auto& texRef = m_Screen_Object.back(); // <-- Get a reference to the pointer.
然后你再用texRef
。这是对您添加到矢量的指针的实际引用,而不是指针的副本。
那么循环就是:
texRef = SDL_CreateTextureFromSurface(Render::Get_Renderer(), surf);
这会更改向量中存储的实际指针。
我对指向变量的指针行为背后的推理感到很困惑。我本以为,如果我将一个指针附加到 vector
并访问它,无论我是否更改了指针本身,它仍然应该对同一个变量起作用。我的意思是,例如,我有一个整数指针向量,我修改了一个在别处定义的变量,该变量已附加到向量中。如果我要打印它们,它应该更新向量(实际上不是)但它应该打印一个整数的新值。我正在尝试将其应用于 SDL2 中的 SDL_Texture*
,但它并没有多大意义。总之,相同的概念也适用于此,但我使用的是纹理。我修改了纹理并用它做“事情”,但是在渲染它的循环结束时,向量仍然迭代到附加到它的 SDL_Texture*
。我的问题是,当我更改和修改纹理时,当我去渲染它时它没有显示出来。这不是因为纹理没有正确加载或任何东西(我已经测试过它并且没有使用矢量,而是原始绘制它)但是当使用矢量时它不能正常工作。这是代码:
void Main::Mainloop()
{
Screen_Object m_Screen_Object;
TTF_Font* font = TTF_OpenFont("Anonymous_Pro.ttf", 30);
SDL_Surface* surf = TTF_RenderText_Blended(font, "Starting fps", {0,0,0});
SDL_Texture* tex = SDL_CreateTextureFromSurface(Render::Get_Renderer(), surf);
SDL_FreeSurface(surf);
SDL_Rect rct = {20, 100, 0,0};
SDL_QueryTexture(tex, NULL, NULL, &rct.w, &rct.h);
m_Screen_Object.Add_Texture(tex);
Uint32 start, finish, counter;
counter = 0;
start = SDL_GetTicks();
finish = SDL_GetTicks();
bool running = true;
while (running)
{
Events::Event_Loop();
if (Events::Quit_Application()){
running = false;
break;
}
///Clear display to color
SDL_SetRenderDrawColor(Render::Get_Renderer(), 0,255,0,255);
SDL_RenderClear(Render::Get_Renderer());
///Do stuff here
m_Screen_Object.Draw_Textures();
finish = SDL_GetTicks();
counter += 2;
if (finish - start >= 500)
{
start = SDL_GetTicks();
SDL_DestroyTexture(tex);
std::string fps = std::to_string(counter);
surf = TTF_RenderText_Blended(font, fps.c_str(), {0,0,0});
tex = SDL_CreateTextureFromSurface(Render::Get_Renderer(), surf);
SDL_FreeSurface(surf);
SDL_QueryTexture(tex, NULL, NULL, &rct.w, &rct.h);
counter = 0;
}
SDL_RenderPresent(Render::Get_Renderer());
}
SDL_DestroyTexture(tex);
TTF_CloseFont(font);
}
int main(int argc, char* argv[])
{
Main::Mainloop();
return 0;
}
这里是 Screen_Object
的声明:
在header:
std::vector < SDL_Texture* > m_Textures;
在.cpp中:
void Screen_Object::Add_Texture(SDL_Texture* p_Texture)
{
m_Textures.push_back(p_Texture);
}
void Screen_Object::Draw_Textures()
{
for (unsigned int i=0; i < m_Textures.size(); i++)
{
SDL_RenderCopy(Render::Get_Renderer(), m_Textures[i], NULL, &m_Rect);
}
}
现在这段代码没有按照我认为应该的方式工作,因为我不明白为什么它不工作,但是当我将向量的类型更改为 SDL_Texture**
时,代码可以工作美好的。没有**
的代码到底有什么问题,我无法从逻辑上理解为什么它不能正常工作
问题似乎是您在向量中存储指针,但在向量外部您使指针无效。
void Screen_Object::Add_Texture(SDL_Texture* p_Texture)
{
m_Textures.push_back(p_Texture);
}
void Main::Mainloop()
{
Screen_Object m_Screen_Object;
//...
SDL_Texture* tex = SDL_CreateTextureFromSurface(Render::Get_Renderer(), surf);
//...
m_Screen_Object.Add_Texture(tex); // <-- add pointer to vector
//...
tex = SDL_CreateTextureFromSurface(Render::Get_Renderer(), surf); // <-- This changes the pointer, but has no effect on the vector's
//...
所以在该行之后的任何内容,如果您访问 m_Textures
向量中的指针,向量中的指针将不再有效,或者更糟的是,它是有效的,但指向一个旧的(但仍然有效) SDL_Texture
.
一个非常简单的解决方案是通过获取对该指针的引用来确保您使用存储在 m_Textures
中的指针:
void Main::Mainloop()
{
Screen_Object m_Screen_Object;
TTF_Font* font = TTF_OpenFont("Anonymous_Pro.ttf", 30);
SDL_Surface* surf = TTF_RenderText_Blended(font, "Starting fps", {0,0,0});
SDL_Texture* tex = SDL_CreateTextureFromSurface(Render::Get_Renderer(), surf);
m_Screen_Object.Add_Texture(tex); // <-- Immediately do this
auto& texRef = m_Screen_Object.back(); // <-- Get a reference to the pointer.
然后你再用texRef
。这是对您添加到矢量的指针的实际引用,而不是指针的副本。
那么循环就是:
texRef = SDL_CreateTextureFromSurface(Render::Get_Renderer(), surf);
这会更改向量中存储的实际指针。