0

[ Answer: While not using push_back (as described in the duplicate thread), improper usage of emplace_back here was triggering the same temp-object-desctructor-used issue. Using emplace_back() instead of emplace_back(Demo()) solved the problem. ]

I'll leave this question un-edited below to show the mistake I had missed, and why this question is having the same problem as the marked-as-duplicate thread, despite using emplace_back instead of push_back.]

(The example below might be clearer than this explanation.)

In a header file I have a struct whose constructor calls glGenVertexArrays() on a member GLuint. In a source file, I emplace_back() an object of that struct into a std::vector.

For some reason, this causes glBindVertexArray() to fail with Invalid Operation.

As a workaround, I can create another function in that struct, and call glGenVertexArrays() from that function instead, and things work. This suggests constructor usage is a problem. Alternatively I can leave the constructor as-is and not use a vector, and things also work. That suggests constructor usage isn't the [only] problem. I can't understand it so my question: Why is vector + constructor usage forcing this workaround?

Example A doesn't work, but Example B does.


ExampleA.h (fails)

    struct Demo
    {
        Demo()
        { 
            glGenVertexArrays(1, &vaoID); 
        }

        GLuint vaoID;
    };

    std::vector<Demo> m_demos;

ExampleA.cpp

    m_demos.emplace_back(Demo());
    glBindVertexArray(m_demos[0].vaoID);   // Fails (but would work if no vector used)

ExampleB.h (works)

    struct Demo
    {
        Demo() { /* do nothing */ }

        void GenerateBuffers()             // Added this workaround
        { 
            glGenVertexArrays(1, &vaoID); 
        }

        GLuint vaoID;
    };

ExampleB.cpp

    m_demos.emplace_back(Demo());
    m_demos[0].GenerateBuffers();          // Added this workaround..
    glBindVertexArray(m_demos[0].vaoID);   // .. which works as desired.
Xenial
  • 465
  • 2
  • 15
  • 1
    Wow, three OpenGL RAII questions in one week. And FYI: if you want to default construct a value in the `vector`, you can just do `emplace_back()`. – Nicol Bolas Oct 21 '17 at 18:29
  • 2
    My question already shows (and refers to) the use of emplace_back(). Since the thread you linked to describes the issue of push_back(), was this mistakenly marked as a duplicate? – Xenial Oct 21 '17 at 18:39
  • 2
    No, it shows the use of `emplace_back(Demo())`. That cause a copy from a temporary. `emplace_back()` *without* the temporary will construct the object in-place. – Nicol Bolas Oct 21 '17 at 19:03
  • Ahhh. Many thanks! And a good lesson about the Rule of 3/5, so cheers. – Xenial Oct 21 '17 at 19:09
  • 1
    Oh and BTW; I said that wrong before. It doesn't cause a copy from the temporary; it moves from it. But unless you wrote a move constructor correctly, it amounts to the same thing. – Nicol Bolas Oct 21 '17 at 19:12
  • Ok, good to be aware of. I was going to suggest it would be worth answering to highlight the improper use of emplace_back here, so it's at least clear to future readers (since the other thread focusses on push_back). I'll highlight it in the Q either way. – Xenial Oct 21 '17 at 19:18

0 Answers0