J'essaie de rendre plusieurs SDL_Rect
s, chacun ayant son propre texte SDL_Texture
et à simple ligne, pour former une boîte de texte à plusieurs lignes. Lorsque son fonctionne CTextInput
fonctionne normalement, puis lorsque j'appuie sur RETURN le texte rend sur la première ligne, puis se bloque soudainement, en signalant une fuite de mémoire.Vecteur retournant une erreur d'exception de mémoire
J'utilise des cours pour résoudre ce problème. Chaque objet CTextBox
a sa propre ligne de texte, étant rendu en SDL_Surface
, puis rendu en SDL_Texture
et SDL_Texture
, soit mTexture
. La classe CTextMenu
est faite pour être la classe administrative. Tous les CTextBox
objets sont stockés dans le boxes
vector, c'est std::vector<CTextBox> boxes
, qui appartient à CMenu
(le principal objet de classe de CTextMenu)
. Lorsque CMenu.update()
est appelé, tous les éléments boxes
obtient rendus dans une boucle for
-SDL_Rect rcTextOutput
.
Voici la boucle for
mentionnée ci-dessus et CTextMenu
classe.
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();
}
}
Il me semble qu'il ya quelque chose de mal sur la façon dont je manipulation mTexture
je posterai les scripts entiers, en-tête et source, ci-dessous.
J'ai aussi couru valgrind et dactylographié text
RETOUR. Il est revenu:
==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)
De plus, s'il y a un moyen de rendre plus efficace une telle zone de texte dans sdl-2, je serai heureux de l'entendre.
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;
}
J'ai ajouté 'it = boxes.begin()' dans le constructeur de la classe comme vous l'avez dit, mais il a la même erreur. Pourriez-vous me donner un exemple de "constructeur correct"? –
Peu importe. J'ai enlevé complètement le 'std :: vector <> :: iterator' et j'ai simplement utilisé' boxes.insert (boxes.begin(), box) '. –
Désolé pour la confusion sur le constructeur, ce conseil était trompeur. Bien que vous devriez toujours vous assurer que tous les membres de votre classe sont correctement initialisés par un constructeur, les itérateurs ne doivent généralement jamais faire partie d'un objet: Les itérateurs se balancent lorsque le conteneur qu'ils itérent réaffectent leur mémoire. En tant que tel, il est dangereux de garder un itérateur pendant une longue période de temps. L'utilisation d'un itérateur dans 'CTextMenu :: newBox()' est ok, la persister dans 'CTextMenu' n'est probablement pas le cas. J'aurais dû y penser avant de taper ma réponse ... – cmaster