-1

I am trying to the following in C++ without using std::string. Here is the code I am trying to use and I would like to not use any deprecated futures.

void Application::_check_gl_error(const char* file, int line)
{
    GLenum err(glGetError());
    while (err != GL_NO_ERROR) {
        char* error;
        switch (err) {
            case GL_INVALID_OPERATION: 
                error = "INVALID_OPERATION";
                break;
        }

        std::cerr << "Error: " << err << " GL_" << error << " - " << file << ":" << line << std::endl;
    }
}

I have read here that in C++ using char* without const and pointing to a string is deprecated.

You should also push the warning level of your compiler up a notch: then it will warn that your first code (i.e. char* str = "name") is legal but deprecated.

however, if I declare const char* error in every case, I get an error in the call to std:cerr that says error: Identifier "error" is not defined

Is there a way for be to conditionally set the value of error here or make it visible for the call to std::cerr?

EDIT: I like the idea of returning a const char* however, that would require calling another function from within check_gl_error to print out the results. I am hoping to avoid that step.

Startec
  • 12,496
  • 23
  • 93
  • 160
  • 2
    What's the problem really? _"In C++ char* is deprecated"_ What does that mean? _"however, if I declare const char* error in every case"_ Why do you do that, and how is it a solution to the preceding? Just use `const char*` exactly where you have it, and just assign to it. Or better, use the conditional operator or a function. – underscore_d Dec 11 '17 at 15:28
  • "In C++ char* is deprecated" is this true? – i486 Dec 11 '17 at 15:28
  • Create a [mcve]. – eerorika Dec 11 '17 at 15:28
  • 4
    `char* error;` -> `const char* error;`. Why would you declare it in every case... – Lundin Dec 11 '17 at 15:28
  • @Startec: Can you show proof that `char *` is deprecated? Pointers are not deprecated AFAIK. – Thomas Matthews Dec 11 '17 at 15:29
  • 2
    Is there a reason you are trying to avoid `std::string` if this is C++ code? – Justin Randall Dec 11 '17 at 15:30
  • 1
    @i486 It's not true. It may be a confused form of "conversion from string literal to `char*` is deprecated", which used to be true until C++11. Since then the conversion has been ill-formed. – eerorika Dec 11 '17 at 15:30
  • 1
    Plain `char*` is not deprecated, you should just not use it for string literals since they are arrays of constant characters. – Some programmer dude Dec 11 '17 at 15:30
  • @ThomasMatthews I added a reference to where I got the idea that `char*` was deprecated in C++. – Startec Dec 11 '17 at 15:34
  • 2
    is it possible that you are confusing `const char *` with `char * const` ? They are quite different... – 463035818_is_not_an_ai Dec 11 '17 at 15:34
  • 1
    Your code has unbalanced `{}`, so won't compile for that reason. Fix those and you might get at the real problem... – Chris Dodd Dec 11 '17 at 15:34
  • 1
    @Startec about the clarifying quote: it says that `char* str = "name"` is deprecated. That's very different from "`char*` is deprecated". Also, the quoted answer has been outdated for a while as `char* str = "name"` is no longer legal since C++11, see my earlier comment. – eerorika Dec 11 '17 at 15:34
  • 1
    @Startec the edited description is still not accurate. It's not deprecated to point to a string with `char*`. It's the implicit conversion from string literal to `char*` that is deprecated (or was deprecated and is now illegal). It's never deprecated to point to anything with any pointer. Besides, it's completely safe to point a string with `char*` or even modify a string, if that string isn't a literal or otherwise const. – eerorika Dec 11 '17 at 16:26
  • @user2079303 and then also safe to point a `char*` at nothing and then change where it points? But in this case, aren't I pointing it to a string literal? – Startec Dec 11 '17 at 16:31
  • 1
    @Startec It's always safe to change where a pointer points, as long as it doesn't violate any invariant. Yes, in this case you point to a string literal. It's not safe, to point to it with `char*` - it's quite a bad idea to do so infact - but it is not "deprecated". – eerorika Dec 11 '17 at 16:34
  • @user2079303 can you briefly explain why it is a bad idea? The length of the literal is know right? How can it be unsafe? – Startec Dec 11 '17 at 16:38
  • 1
    @Startec It's unsafe because string literals are const, but `char*` has no compile time check for preventing writing to the pointed object. Attempting to write to a const object has undefined behaviour. In general, it is a bad idea to point to a const object with a pointer / reference to non-const type. – eerorika Dec 11 '17 at 17:25

3 Answers3

6

"In C++ char* is deprecated" - that's a myth that needs to be busted. A string literal is a const char[] type in C++, and that decays to a const char* in many instances.

Refactoring to a function would be absolutely fine:

const char* error(int err){
    switch (err){
    case 1:
        return "Case one";
    case 2:
        return "Case two";
    }
    return nullptr;
}

For the avoidance of doubt the string literals do not need to be the same length.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
2

The problem has nothing to do with char * -- the problem is that error is defined as local within a nested block, so it is no longer in scope after that block when you try to use it.

Move the declaration of error outside (before) the while loop.

Chris Dodd
  • 119,907
  • 13
  • 134
  • 226
  • Not sure about that if "counting the braces" is anything to do by: the one closing the loop is missing. – Bathsheba Dec 11 '17 at 15:33
  • @Bathsheba: this is a best-guess, based on the error message reported -- the code as posted has unbalanced braces and won't compile. – Chris Dodd Dec 11 '17 at 15:37
  • I fixed a typo. `error` and the call to `std::cout` are both in the while loop – Startec Dec 11 '17 at 15:37
  • Are you sure that code gives you that error message? The error message indicates that `error` has fallen out of scope (or has never been defined). – Chris Dodd Dec 11 '17 at 15:39
  • 1
    Ensure your question includes the exact code and exact error, which should quote a line and column number that corresponds to the code. – underscore_d Dec 11 '17 at 15:40
  • There you have `error` defined as local inside the `switch`, so it can't be used outside of it. Had you posted that code originally, you would have had an answer almost immediately. – Chris Dodd Dec 11 '17 at 16:52
1
const char* errors[] = {
    "Case one",
    "Case two"
};
std::cerr << errors[err - 1];

If your error numbers are not continuous and you have a lot of them, you can use std::unordered_map. You get O(1) access time on average.

If you have very few error codes and your error numbers are not continuous, std::vector with binary search might perform better. You get O(log n) complexity but it beats the unordered_map for small values of n.

Yashas
  • 1,154
  • 1
  • 12
  • 34
  • [complete speculation based on hazy memories of performance comparisons] Might an ordered `map` be better for relatively small sets with numerical keys? – underscore_d Dec 11 '17 at 15:31
  • Why would you use `std::map` over `std::vector` when both provide O(log n) complexity? You get the extra advantage of the vector data being contiguous. – Yashas Dec 11 '17 at 15:34
  • @Yashas If the error codes aren't directly mapped to indices, i.e. 0-indexed and especially contiguous, how would you get the corresponding element? That's where one of the `map`s starts to look quite logical. – underscore_d Dec 11 '17 at 15:36
  • @underscore_d `std::unordered_map` or `std::vector` depending on the size of the dataset. – Yashas Dec 11 '17 at 15:37
  • Just don't use C++11 "auto", it's a brain-damaged feature. – Lundin Dec 11 '17 at 15:38