严重包含在字符串中,除非我将它存储在 C++ 类中
Posted
技术标签:
【中文标题】严重包含在字符串中,除非我将它存储在 C++ 类中【英文标题】:Badly contained in a string except when I store it in C++ class 【发布时间】:2019-07-11 17:45:57 【问题描述】:我正在接受 openGL 编程培训,我想创建自己的课程,让我的生活更轻松。但是,我在 Shader 类中遇到了一个问题。
我的 Shader 类由一个 C++ 字符串(着色器的名称)和另外两个 C 字符串(包含片段和顶点着色器的代码)组成。
然后,在初始化期间,我读取文件以将每个字符存储到我的两个 C 字符串中。此时,这两个变量已正确填充,但如果我尝试通过 getVertex()
方法读取它们,它根本不会显示其中必须包含的内容。
片段和顶点着色器代码必须存放在const GLchar *
中,因为glShaderSource()
用于加载着色器。下面是这个函数的原型:void glShaderSource(GLuint shader, GLsizei count, const GLchar **string, const GLint *length);
。
我已经尝试将基本的const char *
用作const GLchar *
,但它是偶数。
我还尝试将着色器代码存储为 C++ 字符串,并在 main 中将它们转换为 C 字符串,但它不会改变任何内容。
这是我的调试打印代码:
-main.cpp
#include "head.h"
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
int main()
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); //For MacOS
/*Window initialization*/
GLFWwindow* window = glfwCreateWindow(800, 600, "Hello Window!", NULL, NULL);
if (window == NULL)
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
/*GLAD initialization*/
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
/*Initialize shaders*/
Shader myShaders("Hello");
std::cout << "Main Print\n" << myShaders.getVertex() << std::endl;
/*Triangle Vertices*/
/*float vertices[] =
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
;*/
/*Rectangle Vertices*/
float vertices[] =
0.5f, 0.5f, 0.0f, // top right
0.5f, -0.5f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f // top left
;
unsigned int indices[] =
0, 1, 3, // first triangle
1, 2, 3 // second triangle
;
unsigned int VBO;
glGenBuffers(1, &VBO);
/*Define the type of the VBO*/
glBindBuffer(GL_ARRAY_BUFFER, VBO);
/*Copy vertices into the GL_ARRAY_BUFFER object (VBO)*/
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
/*Creating a VS object*/
unsigned int vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
/*Link the VS code to the VS object*/
glShaderSource(vertexShader, 1, &myShaders.getVertex(), NULL);
glCompileShader(vertexShader);
/*Testing the VS compilation*/
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success)
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
/*As the VS, same for FS*/
unsigned int fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &myShaders.getFragment(), NULL);
glCompileShader(fragmentShader);
if (!success)
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
/*Creating the program Shader*/
unsigned int shaderProgram;
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
/*Testing PS compilation*/
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success)
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::COMPILATION_FAILED\n" << infoLog << std::endl;
/*Deleting shaders already used*/
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
/*Activating our shader*/
glUseProgram(shaderProgram);
/*How to interprets data*/
/*(layout (location = 0),vec3,type of the vec,for [-1.0;1.0],stride worked with 0 too, offset to begin*/
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
/*Creating Vertex Array Object*/
unsigned int VAO;
glGenVertexArrays(1, &VAO);
// 1. Lier le Vertex Array Object (VAO)
glBindVertexArray(VAO);
// 2. Copier les sommets dans un tampon pour qu’OpenGL les utilise
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 3. Initialiser les pointeurs d’attributs de sommets
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
/*Creating an EBO for tell the order of vertices to being draw*/
unsigned int EBO;
glGenBuffers(1, &EBO);
/*GL_ELEMENT_ARRAY_BUFFER for EBO*/
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
/*Setting the view*/
glViewport(0, 0, 800, 600);
/*To get a thread style*/
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
/*Render Loop*/
while (!glfwWindowShouldClose(window))
glClearColor(0.5f, 0.3f, 0.6f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
processInput(window);
glUseProgram(shaderProgram);
//glBindVertexArray(VAO);
/*(Kind of primitive to use, begin of vertices tab, end of vertices tab)*/
//glDrawArrays(GL_TRIANGLES, 0, 3);
/*6 for length of EBO*/
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwPollEvents();
glfwSwapBuffers(window);
glfwTerminate();
return 0;
/*Resize*/
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
glViewport(0, 0, width, height);
/*Handle inputs*/
void processInput(GLFWwindow* window)
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
-shader.hpp:
#pragma once
class Shader
public:
Shader(std::string const& name) : name_(name)
std::string tmp;
std::ifstream stream("./shaders/" + name_ + ".fs");
if(stream)
while (stream.good())
tmp += stream.get();
fragment_ = tmp.c_str();
stream.close();
tmp = "";
stream.open("./shaders/" + name_ + ".vs");
if(stream)
while (stream.good())
tmp += stream.get();
vertex_ = tmp.c_str();
stream.close();
std::cout << "Shader Initialization Print\n" << vertex_ << "\n\n";
void initialize()
if (name_.size() > 0)
std::string tmp;
std::ifstream stream("./shaders/" + name_ + ".fs");
if (stream)
while (stream.good())
tmp += stream.get();
fragment_ = tmp.c_str();
stream.close();
tmp = "";
stream.open("./shaders/" + name_ + ".vs");
if (stream)
while (stream.good())
tmp += stream.get();
vertex_ = tmp.c_str();
stream.close();
void setName(std::string const& name)
name_ = name;
std::string getName()
return name_;
void setFragment(std::string const& fragment)
fragment_ = fragment.c_str();
const GLchar* & getFragment()
return fragment_;
void setVertex(std::string const& vertex)
vertex_ = vertex.c_str();
const GLchar* & getVertex()
std::cout << "getVertex() Print\n" << vertex_ << "\n\n";
return vertex_;
private:
std::string name_;
const GLchar * vertex_;
const GLchar * fragment_;
;
-head.h:
#pragma once
#include <iostream>
#include <fstream>
#include <string>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "shader.hpp"
-执行跟踪
Shader Initialization Print
#version 330 core
layout (location = 0) in vec3 aPos;
void main()
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
getVertex() Print
¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
Main Print
¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
getVertex() Print
¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
ERROR::SHADER::VERTEX::COMPILATION_FAILED
0(1) : error C0000: syntax error, unexpected $undefined at token "<undefined>"
ERROR::SHADER::FRAGMENT::COMPILATION_FAILED
0(1) : error C0000: syntax error, unexpected $undefined at token "<undefined>"
ERROR::SHADER::PROGRAM::COMPILATION_FAILED
Vertex info
-----------
0(1) : error C0000: syntax error, unexpected $undefined at token "<undefined>"
(0) : error C2003: incompatible options for link
Fragment info
-------------
0(1) : error C0000: syntax error, unexpected $undefined at token "<undefined>"
(0) : error C2003: incompatible options for link
实际上,我希望在我调用getVertex()
/getFragment()
方法的任何地方都能得到着色器初始化打印。
【问题讨论】:
setFrahment
函数尝试存储临时字符串的c_str ()
。您在代码的各个部分都犯了同样的错误。临时死了会发生什么?字符串数据也消失了。
显而易见的解决方案是使vertex_
和fragment_
C++ 字符串类似于name_
。有什么理由不可以吗?
回复@PaulMcKenzie:那么,我应该直接将数据存储在`` `vertex _``` 和fragment _
变量中而不是使用临时变量吗?
@3t13nn3 不,这无济于事。问题是来自c_str
的返回C 字符串的范围有限。将它存储在任何地方都是危险的,因为根据代码中其他地方发生的情况,它可能会变得无效。
回复@John:我必须使用const GLchar *
在glShaderSource()
函数中直接调用我的getter。但我会尝试将它投射到我的主目录中,但这对我来说并不干净。
【参考方案1】:
首先,当您读取文件时,您必须在读取字符后评估stream.good()
时出现问题,但在将字符添加到字符串之前。注意,.get
在读取字符失败时设置eofbit
,但在读取 kast 字符时不设置:
std::string tmp;
std::ifstream stream("./shaders/" + name_ + ".fs");
while (true)
char c = stream.get();
if (!stream)
break;
tmp += c;
无论如何我建议使用std::istreambuf_iterator
:
std::ifstream stream("./shaders/" + name_ + ".fs");
std::string tmp = std::string(std::istreambuf_iterator<char>(stream), std::istreambuf_iterator<char>());
getVertex
和 getFragment
。应返回对指向着色器代码字符 (const GLchar*&
) 的指针的引用。因此,您必须将着色器代码存储在属性中。我建议将代码放在std::string
中。此外,您还需要一个const GLchar*
类型的属性,它包含一个指向代码的指针,并且可以通过引用返回:
class Shader
public:
// ...
void setVertex(std::string const& vertex)
vertex_ = vertex;
vs_ptr_ = vertex_.c_str();
const GLchar*& getVertex()
return vs_ptr_;
private:
// ...
std::string vertex_;
const GLchar *vs_ptr_;
;
整个班级我的样子如下:
class Shader
public:
Shader(std::string const& name)
: name_(name)
initialize();
void initialize()
if (name_.empty())
return;
std::ifstream stream("./shaders/" + name_ + ".fs");
std::string tmp = std::string(std::istreambuf_iterator<char>(stream), std::istreambuf_iterator<char>());
stream.close();
setFragment(tmp);
stream.open("./shaders/" + name_ + ".vs");
tmp = std::string(std::istreambuf_iterator<char>(stream), std::istreambuf_iterator<char>());
stream.close();
setVertex(tmp);
void setName(std::string const& name)
name_ = name;
std::string getName()
return name_;
void setFragment(std::string const& fragment)
fragment_ = fragment;
fs_ptr_ = fragment_.c_str();
const GLchar*& getFragment()
return fs_ptr_;
void setVertex(std::string const& vertex)
vertex_ = vertex;
vs_ptr_ = vertex_.c_str();
const GLchar*& getVertex()
return vs_ptr_;
private:
std::string name_;
std::string vertex_;
std::string fragment_;
const GLchar *vs_ptr_;
const GLchar *fs_ptr_;
;
【讨论】:
好的,可以了。如果我明白了,问题是关于用于获取 C 字符串指针的字符串的生命周期? @3t13nn3 是的。指针指向“易失性”存储器。它指向一个被销毁的对象的缓冲区。【参考方案2】:这是处理此问题的一种方法。它使用string
并将c_str()
的结果存储在该字符串上。关键是,通过存储指针以及它所基于的字符串,您可以确保指针在字符串有效期间保持有效。
class Shader
public:
void setVertex(std::string const& vertex)
vertex_ = vertex;
vertexPtr_ = vertex_.c_str(); // this must be vertex_ not vertex, otherwise we have exactly the same problem as before
const GLchar* & getVertex()
std::cout << "getVertex() Print\n" << vertex_ << "\n\n";
return vertexPtr_;
private:
string vertex_;
const GLchar* vertexPtr_;
;
这是未经测试的代码。
C++ 不是一种只要可访问数据就保持有效的语言(例如,与 Java 不同)。如果不了解所创建对象的生命周期,就无法编程 C++。您的程序获得了正确的类型,但未能理解指针在您使用时无效。这个版本将字符串和指向它的指针保存在一起,这样两者的生命周期相同。
【讨论】:
以上是关于严重包含在字符串中,除非我将它存储在 C++ 类中的主要内容,如果未能解决你的问题,请参考以下文章