【问题标题】:TTF_RenderText_Solid(...) causes segmentation fault errorTTF_RenderText_Solid(...) 导致分段错误错误
【发布时间】:2020-05-28 13:38:13
【问题描述】:

我正在尝试使用 Text 类来处理基于 c++ SDL2 的程序中的文本。

TTF_RenderText_Solid 在主函数中完美运行,虽然在我的类Text 中,在此行SDL_Surface *surface = TTF_RenderText_Solid( font, text.c_str(), fg ); 中,它会导致一些错误。有时它给我一个分段错误错误,有时它没有。

我调试了代码,TTF_Font *fontstd::string textSDL_Color fg 这三个变量都具有各自的正确值。

我的主要功能:

#include <iostream>

#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>

#include "Text.h"

int main()
{
    try
    {
        SDL_Init( SDL_INIT_VIDEO );
        TTF_Init();

        SDL_Window *window = SDL_CreateWindow( "Window", SDL_WINDOWPOS_CENTERED, 
        SDL_WINDOWPOS_CENTERED, 800, 800, SDL_WINDOW_SHOWN );
        SDL_Renderer *renderer = SDL_CreateRenderer( window, -1, SDL_RENDERER_ACCELERATED );


        TTF_Font *f = TTF_OpenFont( "cruft.ttf", 32 );
        SDL_Surface *s = TTF_RenderText_Solid( f, "Avocado", {0,0,0,255} );
        if(s == NULL)
            std::cout << "s == NULL\n";



        Text title;
        title = Text( renderer, "cruft.ttf", 32, "title" );
        title.render_Text_Solid( "Avocado", {0,0,0,255} );



        SDL_Quit();
        TTF_Quit();

        return 0;
    }
    catch( std::exception& e )
    {
        std::cerr << "Error: " << e.what() << "\n";
        return 0;
    }
    catch(...)
    {
        std::cerr << "Unkown error!\n";
        return 0;
    }
}

我的Text.cpp 文件:

#include <iostream>
#include <string.h>

#include "Text.h"
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>

//Constructors
Text::Text(){}

Text::Text(SDL_Renderer *renderer, std::string file, int ptsize, std::string name)
{
    set_renderer( renderer );
    this->name = name;

    set_TTF_Font( file, ptsize );
}

Text::~Text()
{
    TTF_CloseFont( font );
    SDL_DestroyTexture( texture );
}



void Text::set_renderer( SDL_Renderer *renderer )
{
    if( renderer == NULL )
        throw std::runtime_error( name + ": Renderer could not be set! renderer == NULL\n" + SDL_GetError() );

    this->renderer = renderer;
}

void Text::set_TTF_Font( std::string file, int ptsize )
{
    TTF_CloseFont( font );
    font = NULL;
    SDL_DestroyTexture( texture );
    texture = NULL;
    width = 0;
    height = 0;

    if( file == "" )
        throw std::runtime_error( name + ": TTF_Font* could not be set! file == ""\n" + SDL_GetError() );
    if( ptsize <= 0 )
        throw std::runtime_error( name + ": TTF_Font* could not be set! ptsize <= 0\n" + SDL_GetError() );

    TTF_Font *font = TTF_OpenFont( file.c_str(), ptsize );

    if( font == NULL )
        throw std::runtime_error( name + ": TTF_Font* could not be set! font == NULL\n" + SDL_GetError() );

    this->font = font;
}

void Text::render_Text_Solid( std::string text, SDL_Color fg )
{
    SDL_DestroyTexture( texture );
    texture = NULL;
    width = 0;
    height = 0;

    SDL_Surface *surface = TTF_RenderText_Solid( font, text.c_str(), fg );

    if( surface == NULL )
        throw std::runtime_error( name + ": Text could not be created! surface == NULL\n" + SDL_GetError() );

    texture = SDL_CreateTextureFromSurface( renderer, surface );
    width = surface->w;
    height = surface->h;
    SDL_FreeSurface( surface );

    if( texture == NULL )
        throw std::runtime_error( name + ": Text could not be created! texture == NULL\n" + SDL_GetError() );
}

我的Text.h 文件:

#ifndef TEXT_H_INCLUDED
#define TEXT_H_INCLUDED

#include <iostream>

#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>

class Text
{
    public:

    //constructors
    Text();
    Text(SDL_Renderer *renderer, std::string file, int ptsize, std::string name);
    ~Text();

    void set_renderer( SDL_Renderer *renderer );
    void set_TTF_Font( std::string file, int ptsize );
    void render_Text_Solid( std::string text, SDL_Color fg );

    //render
    void render( int x, int y );
    void render( SDL_Rect *srcrect, SDL_Rect *dstrect );

    //variables
    int width = 0;
    int height = 0;

    private:
    SDL_Renderer *renderer = NULL;
    SDL_Texture *texture = NULL;
    TTF_Font *font = NULL;
    std::string name = "";

};

#endif // TEXT_H_INCLUDED

PS:我使用 Manjaro Linux 和 Codeblocks

【问题讨论】:

  • 您能否分享有关该错误的更多详细信息?
  • @NicoHaase 有关添加的错误的详细信息,感谢您尝试帮助我。

标签: c++ codeblocks sdl-2 sdl-ttf


【解决方案1】:

让我们先看看这些行的作用:

    Text title;
    title = Text( renderer, "cruft.ttf", 32, "title" );

首先创建title,并使用默认构造函数Text::Text() 对其进行初始化,该构造函数为其字段设置默认值。然后,您使用专门的构造函数创建第二个 Text(为清楚起见我们称其为 title1)对象。然后将title1 复制到title - 因为没有定义operator=,所以会生成默认副本。现在您的titletitle1 具有相同的值。并调用title1.~Text(),杀死你的font

你所拥有的是你的title.font 仍然有它以前的值,但它指向已经关闭的字体结构。

这可以通过不构造临时 Text 对象来避免 - 例如Text title = Text(.......) 不会产生临时对象和复制。这只是一种解决方法,实际问题仍然存在 - 您的 Text 对象无法安全复制。有很多方法可以解决这个问题——比如使用某种 unique_ptr 包装器或删除析构函数以支持手动 deinit 方法等。

这给我们带来了下一个问题 - 如果您解决了复制问题,您现在可以生成文本表面和纹理,但请查看您的退出代码:

    Text title;
    // ... omitted
    SDL_Quit();
    TTF_Quit();
    return 0;

您的最终确定是相反的 - 您想要关闭字体、删除纹理、销毁渲染器/窗口,然后调用 TTF_QuitSDL_Quit,但你有 SDL_Quit()、@ 987654342@,只有在那之后title.~Text() - 可能会崩溃,因为 SDL/TTF 已经完成,之后您不应该执行 SDL 调用。当然这也可以解决,例如通过将您的 title 包含在额外的代码块中,但是要注意的事情的数量会变得太大。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-06
    • 2020-12-31
    • 2019-07-21
    • 2018-07-28
    • 2014-04-25
    • 2011-07-18
    • 2013-02-26
    • 2022-01-12
    相关资源
    最近更新 更多