我在很长一段时间后使用cpp进行opengl项目。我面临的问题与cpp特别是与opengl有关。下面的两个代码片段有什么区别?
// this works
std::string tmp = FileIO::read("vertex_shader");
const char *vertexShaderSource = tmp.c_str();
std::cout<< vertexShaderSource <<std::endl; //shows proper value
//but this doesn't work
const char *vertexShaderSource = FileIO::read("vertex_shader").c_str();
std::cout<< vertexShaderSource <<std::endl; //shows garbage value
//FileIO::read() returns a string value
我有点困惑为什么第一个工作但第二个显示垃圾?我错过了什么吗?
请任何cpp专家告诉我第二个代码片段有什么问题以及为什么它不起作用。提前谢谢,
答案 0 :(得分:3)
假设FileIO::read()
按值返回std::string
,那么当您执行
FileIO::read("vertex_shader").c_str()
std::string
返回的FileIO::read
对象是临时。一旦调用了它的c_str()
函数,对象就会超出范围并被破坏,为你留下一个指向不再存在的字符串的指针。
取消引用此指针(当您尝试打印字符串时会发生这种情况)会导致undefined behavior。
答案 1 :(得分:3)
我认为FileIO::read
按值返回,然后FileIO::read("vertex_shader")
会返回temporary std::string
,它将在完整表达式后被销毁。在那之后vertexShaderSource
成为一个悬垂的指针,任何取消引用都会导致UB。即。
const char *vertexShaderSource = FileIO::read("vertex_shader").c_str();
// vertexShaderSource becomes dangled from here
std::cout<< vertexShaderSource <<std::endl; // UB
如果使用命名变量tmp
作为第一个代码示例显示,tmp
将不会被销毁,直到超出其定义的范围;那么代码很好。
答案 2 :(得分:2)
您遇到的问题与变量的生命周期有关。 var rootUrl = new UriBuilder("http", "example.com", 50000).Uri.ToString().TrimEnd('/');
会返回保存字符串的FileIO::read
。
在第一种情况下,您正在复制(实际上由于RVO不能复制任何副本)返回值到变量,然后您将获得指向字符串的char数组的指针。因此,指针指向的内存由std::string
变量拥有。
在第二种情况下,您正在检索指向由tmp
函数返回的临时字符串所拥有的char数组的指针。这为您提供了临时拥有的内存地址。
在该语句完成之后,临时被破坏以及它拥有的所有内存,其中包括您检索并存储在read
中的指针指向的char数组。