2017-05-08 5 views
-2

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, 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 et dactylographié textRETOUR. 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 , 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; 
} 

Répondre

2

L'erreur de 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 

vous dit tout ce que vous devez savoir: Vous appelez std::vector<>::insert() avec un itérateur non initialisé ... Utilisez un itérateur correctement initialisé et valide, et le problème devrait disparaître.

+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"? –

+0

Peu importe. J'ai enlevé complètement le 'std :: vector <> :: iterator' et j'ai simplement utilisé' boxes.insert (boxes.begin(), box) '. –

+0

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