c++中如果在一个函数试图返回一个函数内的变量的时候,请记住不要返回指针,可以返回它的引用给调用者:
原因是:函数一旦执行完毕之后你想返回的那个指针变量其实已经被栈内存自动回收了,你在使用它的时候它其实就成了野指针,指向的内存地址可能根本不存在,这样就会造成程序崩溃,
举个例子:
我再Game.cpp类中定义了一个方法叫init(),在这其中生成了一个shader对象,让后我又把该shader对象传递到另一个类的构造方法中,当渲染方法执行的时候试图使用shader对象,运行报错了:
具体代码:
void Game::Init() {
engine = irrklang::createIrrKlangDevice();
// 播放背景音乐da
engine->play2D("audio/breakout.mp3",true);
// 加载着色器
ResManager::loadShader("s.vs","s.fs",nullptr,"sprite");
// 加载粒子相关的着色器
ResManager::loadShader("p.vs","p.fs",nullptr,"particle");
// 特效着色器
ResManager::loadShader("pt.vs","pt.fs",nullptr,"post");
// 字体着色器
ResManager::loadShader("font.vs","font.fs",nullptr,"font");
// 配置着色器
glm::mat4 projection = glm::ortho(0.0f, static_cast<float>(this->width),static_cast<float>(this->height),0.0f,-1.0f,1.0f);
Shader spriteShader = ResManager::getShaderByName("sprite");
// 将纹理传入着色器
spriteShader.use().setInt("tex",0);
spriteShader.use().setMat4("projection",projection);
Shader particleShader = ResManager::getShaderByName("particle");
particleShader.use().setInt("tex",0);
particleShader.use().setMat4("projection",projection);
Shader postShader = ResManager::getShaderByName("post");
//postShader.setInt("tex",0);
// 存在栈里面的对象变量中传递给一个函数里面一定要注意,fontShader此时已经被回收了,在后续的使用中一定会出现问题
Shader fontShader = ResManager::getShaderByName("font");
// 初始化字体
font = new MyFont(&fontShader);
effects = new PostProcessor(postShader,this->width,this->height);
effects->chaos = false;
effects->confuse = true;
// 当前关卡为1
this->level = 2;
this->sRenderer = new SpriteRenderer(spriteShader);
//SpriteRenderer sr = SpriteRenderer(spriteShader);
// 加载纹理
ResManager::loadTexture("assets/face.png",true,"face");
ResManager::loadTexture("assets/block.png",true,"block");
ResManager::loadTexture("assets/block_solid.png",true,"block_solid");
ResManager::loadTexture("assets/background.jpg",false,"background");
ResManager::loadTexture("assets/paddle.png",true,"paddle");
ResManager::loadTexture("assets/particle.png",true,"particle");
glm::vec2 playerPos = glm::vec2(this->width / 2 - PLAYER_SIZE.x / 2,this->height - 2 * PLAYER_SIZE.y);
player = new GameObject(playerPos, PLAYER_SIZE, ResManager::getTextureByName("paddle"));
// hero
glm::vec2 ballPos = playerPos + glm::vec2(PLAYER_SIZE.x / 2 - BALL_RADIUS, -BALL_RADIUS * 2);
hero = new BallObject(ballPos,BALL_RADIUS,INITIAL_BALL_VELOCITY,ResManager::getTextureByName("face"));
// 加载关卡
GameLevel one, two, three, four;
one.load("level/one.txt",this->width,this->height * 0.5);
two.load("level/two.txt",this->width,this->height * 0.5);
three.load("level/three.txt",this->width,this->height * 0.5);
four.load("level/four.txt",this->width,this->height * 0.5);
this->levels.push_back(one);
this->levels.push_back(two);
this->levels.push_back(three);
this->levels.push_back(four);
// 初始化粒子系统
particles = new ParticleGenerator(ResManager::getShaderByName("particle"),ResManager::getTextureByName("particle"), particleCount);
}
请注意:font = new MyFont(fontShader);
下面是MyFont类:
MyFont::MyFont(Shader* shader) {
//this->fontShader = shader;
this->fontShader = shader;
// 初始化字体
if (FT_Init_FreeType(&this->ft)) {
cout << "could not init freetype library " << endl;
}
if (FT_New_Face(this->ft, "fonts/arial.ttf", 0, &this->face)) {
cout << "failed to load font" << endl;
}
// 定义字体大小 宽度设置为零表示我们要从字体面通过给定的高度中动态的计算字形的宽度
FT_Set_Pixel_Sizes(this->face, 0, 48);
// 默认填充characters
// 禁用字节对齐限制
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
for (uint c = 0; c < 128; c++) {
// 加载字符的字形
if (FT_Load_Char(this->face, c, FT_LOAD_RENDER)) {
cout << "failed to load glyph" << endl;
continue;
}
// 生成纹理
uint texture;
glGenTextures(1,&texture);
glBindTexture(GL_TEXTURE_2D, texture);
// 单个红色分量在着色器中只能取到r红色值的分量
glTexImage2D(GL_TEXTURE_2D,0,GL_RED,this->face->glyph->bitmap.width,this->face->glyph->bitmap.rows,0,GL_RED,GL_UNSIGNED_BYTE,this->face->glyph->bitmap.buffer);
// 设置纹理
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
Character character = {
texture,glm::ivec2(this->face->glyph->bitmap.width,this->face->glyph->bitmap.rows),
glm::ivec2(this->face->glyph->bitmap_left,this->face->glyph->bitmap_top),
this->face->glyph->advance.x
};
this->characters.insert(pair<char, Character>(c, character));
}
/*this->fontShader.use();*/
this->fontShader->use();
glm::mat4 projection = glm::ortho(0.0f, 800.0f, 0.0f, 600.0f);
this->fontShader->setMat4("projection", projection);
this->initRenderData();
}
// 析构函数
MyFont::~MyFont() {
// 清理ft资源
FT_Done_FreeType(this->ft);
// 清理面信息
FT_Done_Face(this->face);
}
// 初始化渲染数据
void MyFont::initRenderData() {
glGenVertexArrays(1,&this->VAO);
glGenBuffers(1,&this->VBO);
glBindBuffer(GL_ARRAY_BUFFER,this->VBO);
glBufferData(GL_ARRAY_BUFFER,sizeof(float) * 6 * 4,NULL,GL_DYNAMIC_DRAW);
glBindVertexArray(this->VAO);
glVertexAttribPointer(0,4,GL_FLOAT,GL_FALSE,4 * sizeof(float),(void*)0);
glEnableVertexAttribArray(0);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER,0);
}
Character MyFont::getCharByName(const char& name) {
return this->characters[name];
}
// 绘制文本
void MyFont::draw(string text,float x,float y,float scale,glm::vec3 color) {
// 启用混合
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
this->fontShader->use();
this->fontShader->setInt("tex",0);
glUniform3f(glGetUniformLocation(this->fontShader->ID,"textColor"),color.x,color.y,color.z);
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(this->VAO);
string::const_iterator c;
for (c = text.begin(); c != text.end(); c++) {
Character ch = characters[*c];
float xpos = x + ch.bearing.x * scale;
float ypos = y - (ch.size.y - ch.bearing.y) * scale;
float w = ch.size.x * scale;
float h = ch.size.y * scale;
// 对每个字符更新VBO
float vertices[6][4] = {
{ xpos, ypos + h, 0.0, 0.0 },
{ xpos, ypos, 0.0, 1.0 },
{ xpos + w, ypos, 1.0, 1.0 },
{ xpos, ypos + h, 0.0, 0.0 },
{ xpos + w, ypos, 1.0, 1.0 },
{ xpos + w, ypos + h, 1.0, 0.0 }
};
glBindTexture(GL_TEXTURE_2D,ch.textureId);
// 更新VBO内容
glBindBuffer(GL_ARRAY_BUFFER,this->VBO);
// 更新之前的buffer一部分数据
glBufferSubData(GL_ARRAY_BUFFER,0,sizeof(vertices),vertices);
glBindBuffer(GL_ARRAY_BUFFER,0);
glDrawArrays(GL_TRIANGLES,0,6);
// 更新下一个字形的x坐标 频繁更新顶点数据 需要GL_DYNAMIC_DRAW
x += (ch.advance >> 6) * scale;
}
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D,0);
}
事故现场就是draw方法里面的下面两句话:
this->fontShader.use();
this->fontShader.setInt("tex",0);
这个fontShader就不是当初通过构造方法传递进来的那个shader了,这就是函数里面返回了一个局部变量惹得祸。