3

I tried to implement unique pointers to non-pointer as described here: One-liner for RAII on non pointer? and https://dzone.com/articles/c11-smart-pointers-are-not . But I always get an compiler error: /usr/include/c++/5/bits/unique_ptr.h:235:12: error: invalid operands of types ‘unsigned int’ and ‘std::nullptr_t’ to binary ‘operator!=’

This is my code:

struct ShaderDeleter
{
    typedef GLuint pointer; // Note the added typedef
    void operator()(GLuint shader) {
        glDeleteShader(shader);
    }
};

int main() {
    std::unique_ptr<GLuint, ShaderDeleter> smart_shader{glCreateShader(GL_VERTEX_SHADER)};
}

What am I doing wrong?

Platform: Ubuntu 16.04

Compiler: g++

Michael Mahn
  • 737
  • 4
  • 11
  • What happens if you simply comment out the `typedef`? – Some programmer dude May 07 '18 at 11:16
  • Compiler error: Test.cpp:26:86: error: no matching function for call to ‘std::unique_ptr::unique_ptr()’ – Michael Mahn May 07 '18 at 11:18
  • Yes, that's why I added the typedef. According to the linked SO question and article, you should be able to use unique_ptr also for non-pointer types if you use a typedef for pointer in the deleter. – Michael Mahn May 07 '18 at 11:26
  • 1
    The article appears to be wrong, as explained in the SO answers you linked. Even if you change `T` in the deleter, it still must satisfy the NullablePointer concept, which is why the code from you or the article [will not work](https://godbolt.org/g/9G22dm): You can't compare a `GLuint` to `nullptr`, which is exactly what the `unique_ptr` constructor does. – Max Langhof May 07 '18 at 11:31
  • 1
    It would be a better idea to wrap `GLuint` into a dedicated wrapper which will also prevent mixing of unrelated values (`GLuint` for shader and `GLuint` for buffer for example). – user7860670 May 07 '18 at 11:38
  • Oh, I see. I'll try a new way then. Thanks! – Michael Mahn May 07 '18 at 11:45

1 Answers1

6

According to C++17 [unique.ptr.single]/3:

[...] The type unique_ptr<T, D>::pointer shall satisfy the requirements of NullablePointer.

Those requirements are found in [nullablepointer.semantics], which is summarised here. In brief, the type must allow comparison to nullptr. So an integer cannot be used as the type.

The code in your non-SO link is ill-formed. The code in the answer by "fjoanis" in the SO link is also ill-formed.


Instead, you could use one of the other solutions to that question. IMHO unique_ptr is not suitable for this task. There is a proposal P0052 for something called std::unique_resource designed for this purpose.

I will probably get downvoted for mentioning this, but perhaps you could try using void * as the pointer type , and casting the GLuint to void *. In general such a cast is non-portable and may cause a runtime exception, but on common x86 platforms you probably get away with it. Link to example that compiles.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • 1
    Instead of going into the dragons territory and dealing with possible [fun](http://dwarffortresswiki.org/index.php?title=DF2014:Fun&redirect=yes), maybe it would be possible and relatively easy to provide a lightweight nullable box something like [here](https://godbolt.org/g/8Yrrs1) I am thinking of making a supplementary answer to yours with the code, so it's easily accessible on-site. I used `int` but it should be easy enough to translate it to `GLuint` or template the type and the null value. It seems to work as expected. – luk32 May 07 '18 at 14:17
  • @luk32 maybe you could post it on [this thread](https://stackoverflow.com/questions/24611215/one-liner-for-raii-on-non-pointer) – M.M May 07 '18 at 23:25