4

This is a snippet from OpenGL Super Bible 7th edition:

GLint log_length;
glGetShaderiv(fs, GL_INFO_LOG_LENGTH, &log_length);
std::string str;
str.reserve(log_length);
glGetShaderInfoLog(fs, log_length, NULL, str.c_str());

At a first glance it seemed weird to me to pass str.c_str() as an argument to this function, and of course clang immediatelly protested: cannot initialize a parameter of type 'GLchar *' (aka 'char *') with an rvalue of type 'const char *'.

So I tried to investigate and changed str.c_str() to str.data(), which should provide a pointer to the internal data array, but this produces the same error message. Edit: c_str() and data() are actually the same thing (in c++11 at least), so it doesn't matter which one we use.

I did some searches, but didn't find a solution (although I'm quite new to C++ and some things are still not obvious to me).

Is this an error in the book? And is there a way to make it work with std::string?

Paweł Pela
  • 421
  • 3
  • 16
  • @Asu actually, `c_str()` and `data()` are the same thing and they both return `const char*`. I also thought that `data()` returned `char*` without the `const`. – Paweł Pela Oct 23 '16 at 19:28
  • 1
    After some verification, `c_str()` always does return a `const char*` and since C++17 `data()` can return a `char*`. Sounds like you're going to need a C++17 compliant compiler that supports this yet or find an alternative. – asu Oct 23 '16 at 19:28
  • 1
    I [asked](http://stackoverflow.com/questions/35203117/misuse-of-gl-info-log-null-terminating-character-in-stdstring) a related question a while back. `& str[0]` is the easy way to access the storage, but be careful of NUL termination and length assumptions. – Brett Hale Oct 24 '16 at 04:52
  • Try `const_cast`?(NOTE: that can makes your code messy) `const_cast(some_const_char_pointer)` –  Mar 08 '22 at 08:51

1 Answers1

6

Both string::c_str() and string::data() return a const char* until C++17. Since C++17, string::data() has an overload that will return a char*. This means this code snippet is invalid.

Edit: An easier and as efficient solution is to use &str[0]. The subscript operator will return a char&.

If you cannot use C++17, you could use a std::vector<char>, which does have a non-const data(), but this will cause a copy when constructing a std::string:

// ...
std::vector<char> v(log_length);
glGetShaderInfoLog(fs, log_length, NULL, v.data());
std::string s(begin(v), end(v));

Also, reserve() isn't sufficient, because the actual size() is not changed. If c_str() returned a char*, the snippet would actually also cause undefined behavior.

asu
  • 1,875
  • 17
  • 27