返回内存异常错误的矢量

Vector returning a memory exception error

本文关键字:错误 内存 异常 返回      更新时间:2023-10-16

我正在尝试渲染多个SDL_Rect,每个都有自己的SDL_Texture和单行文本,以形成一个多行文本框。当它运行时CTextInput正常工作,然后当我按RETURN时,文本呈现到第一行,然后突然崩溃,报告内存泄漏。

我正在使用类来解决这个问题。每个CTextBox对象都有自己的文本行,被渲染成一个SDL_Surface,然后被渲染成一个SDL_TextureSDL_Texture,被mTexture。类CTextMenu被设置为管理类。所有CTextBox对象都存储在boxes向量中,这是std::vector<CTextBox> boxes,它由CMenu(CTextMenu)的主类对象)拥有。调用CMenu.update()时,boxes中的所有元素都会在for循环中呈现以SDL_Rect rcTextOutput

下面是前面提到的for循环和CTextMenu类:

class CTextMenu
{
std::vector<CTextBox> boxes;
std::vector<CTextBox>::iterator it;
public:
void update(SDL_Renderer *renderer, TTF_Font *font, SDL_Color color, SDL_Rect output);
void newBox(std::string text);
};
void CTextMenu::update(SDL_Renderer *renderer, TTF_Font *font, SDL_Color color, SDL_Rect output)
{
SDL_RenderSetClipRect(renderer, &output);
for (unsigned int i = 0; i < boxes.(); i++)
{
boxes[i].render(renderer, font, boxes[i].text, color);
SDL_Rect dstrect;
dstrect.x = 0;
dstrect.y = 600 + i * boxes[i].getHeight();
dstrect.w = boxes[i].getWidth();
dstrect.h = boxes[i].getHeight();
SDL_RenderCopy(renderer, boxes[i].getTexture(), NULL, &dstrect);
}
}
void CTextMenu::newBox(std::string text)
{
CTextBox box;
box.text = text;
boxes.insert(it, box);
if (boxes.size() > 14)
{
boxes.pop_back();
}
}

在我看来,我如何处理mTexture有问题.我将在下面发布整个脚本、标题和源代码。

我还运行了valgrind并输入了textRETURN。它返回:

==3485== Memcheck, a memory error detector
==3485== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==3485== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==3485== Command: build/./caventure
==3485== 
==3485== Syscall param writev(vector[...]) points to uninitialised byte(s)
==3485==    at 0x5CF218D: ??? (in /usr/lib/libc-2.25.so)
==3485==    by 0x8088BAC: ??? (in /usr/lib/libxcb.so.1.1.0)
==3485==    by 0x8088FAC: ??? (in /usr/lib/libxcb.so.1.1.0)
==3485==    by 0x808902C: xcb_writev (in /usr/lib/libxcb.so.1.1.0)
==3485==    by 0x7D7EF3D: _XSend (in /usr/lib/libX11.so.6.3.0)
==3485==    by 0x7D7F431: _XReply (in /usr/lib/libX11.so.6.3.0)
==3485==    by 0x7D6A2EE: XInternAtom (in /usr/lib/libX11.so.6.3.0)
==3485==    by 0x4EFB79A: ??? (in /usr/lib/libSDL2-2.0.so.0.4.1)
==3485==    by 0x4EFC694: ??? (in /usr/lib/libSDL2-2.0.so.0.4.1)
==3485==    by 0x4EEB87F: ??? (in /usr/lib/libSDL2-2.0.so.0.4.1)
==3485==    by 0x4EEB60E: ??? (in /usr/lib/libSDL2-2.0.so.0.4.1)
==3485==    by 0x4E4F1C6: ??? (in /usr/lib/libSDL2-2.0.so.0.4.1)
==3485==  Address 0x79c5573 is 35 bytes inside a block of size 16,384 alloc'd
==3485==    at 0x4C2CF35: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3485==    by 0x7D6F385: XOpenDisplay (in /usr/lib/libX11.so.6.3.0)
==3485==    by 0x4EFA84F: ??? (in /usr/lib/libSDL2-2.0.so.0.4.1)
==3485==    by 0x4EEB5BB: ??? (in /usr/lib/libSDL2-2.0.so.0.4.1)
==3485==    by 0x4E4F1C6: ??? (in /usr/lib/libSDL2-2.0.so.0.4.1)
==3485==    by 0x402002: init() (in /home/pradana/Projects/sierra/caventure/build/caventure)
==3485==    by 0x402333: main (in /home/pradana/Projects/sierra/caventure/build/caventure)
==3485== 
==3485== Invalid write of size 4
==3485==    at 0x402BEC: CTextBox::CTextBox(CTextBox const&) (in /home/pradana/Projects/sierra/caventure/build/caventure)
==3485==    by 0x403B6B: void __gnu_cxx::new_allocator<CTextBox>::construct<CTextBox, CTextBox const&>(CTextBox*, CTextBox const&) (in /home/pradana/Projects/sierra/caventure/build/caventure)
==3485==    by 0x4030EE: void std::allocator_traits<std::allocator<CTextBox> >::construct<CTextBox, CTextBox const&>(std::allocator<CTextBox>&, CTextBox*, CTextBox const&) (in /home/pradana/Projects/sierra/caventure/build/caventure)
==3485==    by 0x4037FB: void std::vector<CTextBox, std::allocator<CTextBox> >::_M_insert_aux<CTextBox const&>(__gnu_cxx::__normal_iterator<CTextBox*, std::vector<CTextBox, std::allocator<CTextBox> > >, CTextBox const&) (in /home/pradana/Projects/sierra/caventure/build/caventure)
==3485==    by 0x402E16: std::vector<CTextBox, std::allocator<CTextBox> >::insert(__gnu_cxx::__normal_iterator<CTextBox const*, std::vector<CTextBox, std::allocator<CTextBox> > >, CTextBox const&) (in /home/pradana/Projects/sierra/caventure/build/caventure)
==3485==    by 0x401F9F: CTextMenu::newBox(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (in /home/pradana/Projects/sierra/caventure/build/caventure)
==3485==    by 0x4027A6: main (in /home/pradana/Projects/sierra/caventure/build/caventure)
==3485==  Address 0xfffffffff6221c30 is not stack'd, malloc'd or (recently) free'd
==3485== 
==3485== 
==3485== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==3485==  Access not within mapped region at address 0xFFFFFFFFF6221C30
==3485==    at 0x402BEC: CTextBox::CTextBox(CTextBox const&) (in /home/pradana/Projects/sierra/caventure/build/caventure)
==3485==    by 0x403B6B: void __gnu_cxx::new_allocator<CTextBox>::construct<CTextBox, CTextBox const&>(CTextBox*, CTextBox const&) (in /home/pradana/Projects/sierra/caventure/build/caventure)
==3485==    by 0x4030EE: void std::allocator_traits<std::allocator<CTextBox> >::construct<CTextBox, CTextBox const&>(std::allocator<CTextBox>&, CTextBox*, CTextBox const&) (in /home/pradana/Projects/sierra/caventure/build/caventure)
==3485==    by 0x4037FB: void std::vector<CTextBox, std::allocator<CTextBox> >::_M_insert_aux<CTextBox const&>(__gnu_cxx::__normal_iterator<CTextBox*, std::vector<CTextBox, std::allocator<CTextBox> > >, CTextBox const&) (in /home/pradana/Projects/sierra/caventure/build/caventure)
==3485==    by 0x402E16: std::vector<CTextBox, std::allocator<CTextBox> >::insert(__gnu_cxx::__normal_iterator<CTextBox const*, std::vector<CTextBox, std::allocator<CTextBox> > >, CTextBox const&) (in /home/pradana/Projects/sierra/caventure/build/caventure)
==3485==    by 0x401F9F: CTextMenu::newBox(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (in /home/pradana/Projects/sierra/caventure/build/caventure)
==3485==    by 0x4027A6: main (in /home/pradana/Projects/sierra/caventure/build/caventure)
==3485==  If you believe this happened as a result of a stack
==3485==  overflow in your program's main thread (unlikely but
==3485==  possible), you can try to increase the size of the
==3485==  main thread stack using the --main-stacksize= flag.
==3485==  The main thread stack size used in this run was 8388608.
==3485== 
==3485== HEAP SUMMARY:
==3485==     in use at exit: 14,025,073 bytes in 36,583 blocks
==3485==   total heap usage: 210,985 allocs, 174,402 frees, 97,089,179 bytes allocated
==3485== 
==3485== LEAK SUMMARY:
==3485==    definitely lost: 16 bytes in 1 blocks
==3485==    indirectly lost: 176 bytes in 4 blocks
==3485==      possibly lost: 4,262,172 bytes in 30,166 blocks
==3485==    still reachable: 9,762,709 bytes in 6,412 blocks
==3485==         suppressed: 0 bytes in 0 blocks
==3485== Rerun with --leak-check=full to see details of leaked memory
==3485== 
==3485== For counts of detected and suppressed errors, rerun with: -v
==3485== Use --track-origins=yes to see where uninitialised values come from
==3485== ERROR SUMMARY: 6 errors from 2 contexts (suppressed: 0 from 0)

另外,如果有更有效的方法在 sdl-2 中呈现这样的文本框,我将很高兴听到它。


GFX.H

#ifndef __GFX_H__
#define __GFX_H__
#include <vector>
#include <string>
#include <stdexcept>
#include <algorithm>
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
class CTextBox
{
public:
CTextBox();
~CTextBox();
void free();
void render(SDL_Renderer* renderer, TTF_Font* font, std::string text, SDL_Color color);
int getWidth();
int getHeight();
SDL_Texture* getTexture();
std::string text;
private:
SDL_Texture* mTexture;
int mWidth;
int mHeight;
};
CTextBox::CTextBox()
{
mTexture = NULL;
mWidth = 800;
mHeight = 20;
text = " ";
}
void CTextBox::free()
{
if (mTexture != NULL)
{
SDL_DestroyTexture(mTexture);
mTexture = NULL;
}
}
CTextBox::~CTextBox()
{
free();
}
void CTextBox::render(SDL_Renderer* renderer, TTF_Font* font, std::string text, SDL_Color color)
{
free();
SDL_Surface* TextSurface = TTF_RenderText_Solid(font, text.c_str(), color);
if (TextSurface == NULL)
{
throw(::std::runtime_error("Unable to render surface! ERROR: "));
}
mTexture = SDL_CreateTextureFromSurface(renderer, TextSurface);
if (mTexture == NULL)
{
throw(::std::runtime_error("Unable to render texture! ERROR: "));
}
SDL_FreeSurface(TextSurface);
SDL_QueryTexture(mTexture, NULL, NULL, &mWidth, &mHeight);
}
int CTextBox::getWidth()
{
return mWidth;
}
int CTextBox::getHeight()
{
return mHeight;
}
SDL_Texture* CTextBox::getTexture()
{
return mTexture;
}
class CTextMenu
{
std::vector<CTextBox> boxes;
std::vector<CTextBox>::iterator it;
public:
void update(SDL_Renderer *renderer, TTF_Font *font, SDL_Color color, SDL_Rect output);
void newBox(std::string text);
};
void CTextMenu::update(SDL_Renderer *renderer, TTF_Font *font, SDL_Color color, SDL_Rect output)
{
SDL_RenderSetClipRect(renderer, &output);
for (unsigned int i = 0; i < boxes.(); i++)
{
boxes[i].render(renderer, font, boxes[i].text, color);
SDL_Rect dstrect;
dstrect.x = 0;
dstrect.y = 600 + i * boxes[i].getHeight();
dstrect.w = boxes[i].getWidth();
dstrect.h = boxes[i].getHeight();
SDL_RenderCopy(renderer, boxes[i].getTexture(), NULL, &dstrect);
}
}
void CTextMenu::newBox(std::string text)
{
CTextBox box;
box.text = text;
boxes.insert(it, box);
if (boxes.size() > 14)
{
boxes.pop_back();
}
}
#endif

GFX.cpp

#include <stdio.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#include "gfx.h"
// Screen dimensions, constants
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 900; // 600 for ground, 280 for output, 20 for input
SDL_Window* gWindow = NULL; // The window we'll be rendering to
SDL_Surface* gScreenSurface = NULL; // The surface contained by the window
SDL_Surface* gCurrentSurface = NULL; // Current displayed image
TTF_Font* gFont = NULL; // Font pointer.
SDL_Color gTextColor = { 255, 255, 255, 0xFF }; // Text color, white.
CTextMenu CMenu;
CTextBox CTextInput;
SDL_Renderer* gRenderer = NULL; // The renderer we'll be using
SDL_Rect rcGround, rcSprite, rcTextInput, rcTextOutput, rcTextOutputGrd;
void init();
void loadMedia();
void quit();
void init()
{
if (SDL_Init(SDL_INIT_VIDEO) > 0)
{
throw(::std::runtime_error("SDL failed to initialise! ERROR: "));
}
else
{
gWindow = SDL_CreateWindow("Caventure",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
SCREEN_WIDTH,
SCREEN_HEIGHT,
SDL_WINDOW_SHOWN);
if (gWindow == NULL)
{
throw(::std::runtime_error("Window failed to initialise! ERROR: "));
}
else
{
gScreenSurface = SDL_GetWindowSurface(gWindow);
}
gRenderer = SDL_CreateRenderer(gWindow,
-1,
0);
if (gRenderer == NULL)
{
throw(::std::runtime_error("Renderer could not be initialised! ERROR: "));
}
if (TTF_Init() > 0)
{
throw(::std::runtime_error("TTF could not be initialised! ERROR: "));
}
}
}
void loadMedia()
{
// Ground rendering
rcGround.x = 0;
rcGround.y = 0;
rcGround.w = 800;
rcGround.h = 600;
// Sprite rendering
rcSprite.x = 400;
rcSprite.y = 300;
rcSprite.w = 4;
rcSprite.h = 4;
// TextOutput box rendering
rcTextOutput.x = 0;
rcTextOutput.y = 600;
rcTextOutput.w = 800;
rcTextOutput.h = 280;
// TextOutput box rendering
rcTextOutputGrd.x = 0;
rcTextOutputGrd.y = 600;
rcTextOutputGrd.w = 800;
rcTextOutputGrd.h = 280;
gFont = TTF_OpenFont("src/graphics/resources/notomono-regular.ttf", 14);
if (gFont == NULL)
{
throw(::std::runtime_error("Font load error"));
}
SDL_SetTextInputRect(&rcTextInput);
}
void quit()
{
// Destroy window
SDL_DestroyWindow(gWindow);
SDL_DestroyRenderer(gRenderer);
TTF_CloseFont(gFont);
gWindow = NULL;
gRenderer = NULL;
gFont = NULL;
// Quit SDL subsystems
TTF_Quit();
SDL_Quit();
}
int main()
{
try
{
init();
loadMedia();
bool quit = false;
bool renderText = false;
SDL_Event event;
std::string inputText = " ";
std::string inputCmd = "";
SDL_StartTextInput();
while(!quit)
{
while(SDL_PollEvent(&event) != 0)
{
if(event.type == SDL_QUIT)
{
quit = true;
}
else if(event.type == SDL_KEYDOWN)
{
switch(event.key.keysym.sym)
{
case SDLK_UP:
rcSprite.y -= 5;
break;
case SDLK_DOWN:
rcSprite.y += 5;
break;
case SDLK_LEFT:
rcSprite.x -= 5;
break;
case SDLK_RIGHT:
rcSprite.x += 5;
break;
}
if (event.key.keysym.sym == SDLK_BACKSPACE && inputText.length() > 0)
{
inputText.pop_back();
if (inputText.length() == 0)
{
inputText = " ";
}
}
else if (event.key.keysym.sym == SDLK_RETURN && inputText.length() != 0)
{
inputCmd = inputText.c_str();
renderText = true;
inputText = " ";
}
}
else if (event.type == SDL_TEXTINPUT)
{
inputText += event.text.text;
}
}
if (rcSprite.x < 0 || rcSprite.y < 0 || rcSprite.y > rcGround.h || rcSprite.x > rcGround.w)
{
rcSprite.x = 400;
rcSprite.y = 300;
}
SDL_SetRenderDrawColor(gRenderer, 0x00, 0x00, 0x00, 0x00);
SDL_RenderClear(gRenderer);
SDL_RenderFillRect(gRenderer, &rcGround);
SDL_BlitSurface(gCurrentSurface, NULL, gScreenSurface, &rcGround);
SDL_SetRenderDrawColor(gRenderer, 0x40, 0x40, 0x40, 0x40);
SDL_RenderFillRect(gRenderer, &rcTextOutputGrd);
SDL_BlitSurface(gCurrentSurface, NULL, gScreenSurface, &rcTextOutputGrd);
// Text input
CTextInput.render(gRenderer, gFont, inputText.c_str(), gTextColor);
rcTextInput.x = 0;
rcTextInput.y = 880;
rcTextInput.w = CTextInput.getWidth();
rcTextInput.h = CTextInput.getHeight();
SDL_RenderCopy(gRenderer, CTextInput.getTexture(), NULL, &rcTextInput);
if (renderText)
{
// Text output
CMenu.newBox(inputCmd.c_str());
CMenu.update(gRenderer, gFont, gTextColor, rcTextOutput);
}
SDL_RenderSetClipRect(gRenderer, NULL);
SDL_SetRenderDrawColor(gRenderer, 0xFF, 0xFF, 0xFF, 0xFF);
SDL_RenderDrawLine(gRenderer, 0, 600, 800, 600);
SDL_RenderDrawLine(gRenderer, 0, 880, 800, 880);
SDL_RenderFillRect(gRenderer, &rcSprite);
SDL_BlitSurface(gCurrentSurface, NULL, gScreenSurface, &rcSprite);
SDL_RenderPresent(gRenderer);
}
SDL_StopTextInput();
}
catch (std::runtime_error const& msg)
{
printf("%s", msg.what());
if (SDL_GetError() != NULL)
{
printf("%s", SDL_GetError());
}
else if (TTF_GetError() != NULL)
{
printf("%s", TTF_GetError());
}
else
{
printf("%s", "NULL");
}
quit();
exit(EXIT_FAILURE);
}
quit();
return 0;
}

valgrind 错误

==3485== Invalid write of size 4
==3485==    at 0x402BEC: CTextBox::CTextBox(CTextBox const&) (in /home/pradana/Projects/sierra/caventure/build/caventure)
==3485==    by 0x403B6B: void __gnu_cxx::new_allocator<CTextBox>::construct<CTextBox, CTextBox const&>(CTextBox*, CTextBox const&) (in /home/pradana/Projects/sierra/caventure/build/caventure)
==3485==    by 0x4030EE: void std::allocator_traits<std::allocator<CTextBox> >::construct<CTextBox, CTextBox const&>(std::allocator<CTextBox>&, CTextBox*, CTextBox const&) (in /home/pradana/Projects/sierra/caventure/build/caventure)
==3485==    by 0x4037FB: void std::vector<CTextBox, std::allocator<CTextBox> >::_M_insert_aux<CTextBox const&>(__gnu_cxx::__normal_iterator<CTextBox*, std::vector<CTextBox, std::allocator<CTextBox> > >, CTextBox const&) (in /home/pradana/Projects/sierra/caventure/build/caventure)
==3485==    by 0x402E16: std::vector<CTextBox, std::allocator<CTextBox> >::insert(__gnu_cxx::__normal_iterator<CTextBox const*, std::vector<CTextBox, std::allocator<CTextBox> > >, CTextBox const&) (in /home/pradana/Projects/sierra/caventure/build/caventure)
==3485==    by 0x401F9F: CTextMenu::newBox(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (in /home/pradana/Projects/sierra/caventure/build/caventure)
==3485==    by 0x4027A6: main (in /home/pradana/Projects/sierra/caventure/build/caventure)
==3485==  Address 0xfffffffff6221c30 is not stack'd, malloc'd or (recently) free'd

告诉您您需要知道的一切:您正在使用未初始化的迭代器调用std::vector<>::insert()...使用正确初始化的、仍然有效的迭代器,问题应该就消失了。