ओपन बिल्ड बफर ऑब्जेक्ट्स की सरणी के लिए C ++ रैपर क्लास - बस कंस्ट्रक्टर

Aug 18 2020

ऐसा ही एक प्रश्न पूछा गया था यहाँ है, और मैं एक ही बात करने के लिए कोशिश कर रहा हूँ। परंतु

  1. मैं एक अलग दृष्टिकोण से कोशिश कर रहा हूँ std::array, और
  2. यह केवल कंस्ट्रक्टरों के बारे में एक बहुत ही केंद्रित प्रश्न है।

यहाँ मेरा है gl_wrap.h:

// header guards snipped

#include <array>
#include <algorithm>
#include <cstring>
#include <GL/gl.h>

namespace gl_wrap {

// aliases for style consistency and to mark as parts of gl_wrap
using gl_name = GLuint;
using gl_enum = GLenum;

template<size_t N>
class buffer_objects : public std::array<gl_name, N> {
public:
    buffer_objects() noexcept;
    ~buffer_objects();
    buffer_objects(const buffer_objects&) = delete;
    buffer_objects operator=(const buffer_objects&) = delete;
    buffer_objects(buffer_objects&& from) noexcept;
    buffer_objects& operator=(buffer_objects&& from) noexcept;
};

template<size_t N>
buffer_objects<N>::buffer_objects() noexcept
{
    glGenBuffers(N, this->data());
}

template<size_t N>
buffer_objects<N>::~buffer_objects()
{
    glDeleteBuffers(N, this->data());
}

template<size_t N>
buffer_objects<N>::buffer_objects(buffer_objects<N>&& from) noexcept
    : std::array<gl_name, N>(std::move(from))
{
    memset(from.data(), 0, N * sizeof(gl_name));
}

template<size_t N>
buffer_objects<N>& buffer_objects<N>::operator=(buffer_objects<N>&& from)
    noexcept
{
    std::array<gl_name, N>::operator=(std::move(from));
    memset(from.data(), 0, N * sizeof(gl_name));
    return *this;
}

}
// namespace gl_wrap

इस कोड के बारे में कुछ विशिष्ट प्रश्न / दृष्टिकोण, यदि लागू हो,

  1. डिज़ाइन के निर्णय को संभालने में त्रुटि: क्या कंस्ट्रक्टरों को फेंकना चाहिए, या क्या मुझे कॉल करने के लिए त्रुटि की जाँच करनी चाहिए?
  2. डिजाइन का निर्णय: क्या यहां टेम्पलेट्स का उपयोग करना एक अच्छा विचार है? अगर मैं बहुत अलग-अलग आकार का उपयोग कर रहा हूं, तो क्या यह समस्याग्रस्त कोड ब्लोट की ओर ले जाएगा buffer_objects, या यह कुशल है? क्या मैं प्रोफाइलिंग के माध्यम से इसका मूल्यांकन कर सकता हूं?
  3. क्या memcpyइसके लायक हैं कि प्रतिद्वंद्वियों को वैध गैर-स्वामित्व वाले राज्य में रखा जाए, या क्या मैं प्रतिद्वंद्वियों को गैर-स्वामित्व वाले बचे हुए लोगों के रूप में मान सकता हूं?
  4. क्या मैं बेस क्लास के मूव कंस्ट्रक्टर का सही इस्तेमाल कर रहा हूं?

जवाब

5 MartinYork Aug 18 2020 at 04:43

इस कोड के बारे में कुछ विशिष्ट प्रश्न / दृष्टिकोण, यदि लागू हो,

ठीक।

डिज़ाइन के निर्णय को संभालने में त्रुटि: क्या कंस्ट्रक्टरों को फेंकना चाहिए, या क्या मुझे कॉल करने के लिए त्रुटि की जाँच करनी चाहिए?

या तो ऑब्जेक्ट सही ढंग से आरंभीकृत है और उपयोग करने के लिए तैयार है या इसे फेंक देना चाहिए। दो चरण के आरंभीकरण (फिर निर्माण की जाँच) एक बुरा विचार है क्योंकि यह उपयोगकर्ता को सही काम करने के लिए खुला छोड़ देता है। आपको यह सुनिश्चित करना चाहिए कि आपकी वस्तु का दुरुपयोग नहीं किया जा सकता है जो उपयोगकर्ता पर भरोसा नहीं करता है कि वह आपको गाली न दे।

डिजाइन का निर्णय: क्या यहां टेम्पलेट्स का उपयोग करना एक अच्छा विचार है?

यदि आप उपयोग करने जा रहे हैं std::arrayतो आपके पास वास्तव में कोई विकल्प नहीं है।

अगर मैं बहुत अलग-अलग आकार के बफर_बॉजेक्ट्स का उपयोग कर रहा हूं, तो क्या यह समस्याग्रस्त कोड ब्लोट की ओर ले जाएगा, या यह कुशल है? क्या मैं प्रोफाइलिंग के माध्यम से इसका मूल्यांकन कर सकता हूं?

संभावित रूप से यह विभिन्न प्रकारों के लिए संकलित तरीकों को जन्म देगा। लेकिन यह कंपाइलर निर्भर है और कुछ आधुनिक कंपाइलर इसे बाहर अनुकूलित कर सकते हैं। लेकिन आप इसकी क्या तुलना कर रहे हैं?

क्या मान्यताओं के लायक हैं कि वे वैध गैर-स्वामित्व वाली स्थिति में प्रतिद्वंद्वियों को डाल सकते हैं, या क्या मैं प्रतिद्वंद्वियों को गैर-स्वामित्व वाले बचे हुए के रूप में मान सकता हूं?

मुझे लगता है कि आपको srcमूल्यों को शून्य करने की आवश्यकता है । अन्यथा विध्वंसक नाम जारी करने जा रहा है। वैकल्पिक रूप से आप इस बारे में अधिक स्थिति संग्रहीत कर सकते हैं कि क्या ऑब्जेक्ट वैध है और ऑब्जेक्ट को मान्य glDeleteBuffers()स्थिति में होने पर कॉल करें ।

लेकिन मुझे यह भी लगता है कि यहां एक बग है। आपने अभी मूल्यों पर प्रतिलिपि बनाई है। लेकिन आपने dstप्रतिलिपि से पहले साइड पर मान जारी नहीं किया था इसलिए आपने वहां संग्रहीत नामों को खो दिया है।

याद रखें कि एक std :: array का अपना कोई मूव नहीं है (जैसा कि डेटा स्थानीय रूप से ऑब्जेक्ट के लिए डायनामिक रूप से आवंटित नहीं है)। यह कंटेनर के बीच अंतर्निहित वस्तुओं को स्थानांतरित करता है।

क्या मैं बेस क्लास के मूव कंस्ट्रक्टर का सही इस्तेमाल कर रहा हूं?

हाँ, यह लग रहा है।

सुझाव

मैं std::arrayएक सदस्य बनाऊंगा बल्कि उससे विरासत में मिला हूं ।

मुझे क्या करना होगा:

#ifndef THORSANVIL_GL_WRAPPER_H
#define THORSANVIL_GL_WRAPPER_H

#include <GL/gl.h>
#include <array>
#include <algorithm>
#include <cstring>

namespace ThorsAnvil::GL {

template<size_t N>
class BufferObjects
{
    std::array<GLuint, N>  buffer;
    bool                   valid;
    public:
        BufferObjects() noexcept;
       ~BufferObjects();

        // Note: These are non copyable objects.
        //       Deleting the copy operations.
        BufferObjects(BufferObjects const&)           = delete;
        BufferObjects operator=(BufferObjects const&) = delete;

        // Note: The move is as expensive as a copy operation.
        //       But we are doing a logical move as you 
        //       can not have two objects with the same resource.
        BufferObjects(BufferObjects&& from)            noexcept;
        BufferObjects& operator=(BufferObjects&& from) noexcept;

        // Reset an invalid object.
        // Note: If object is valid no action.
        void reset();

};

template<size_t N>
BufferObjects<N>::BufferObjects() noexcept
    : valid(false)
{
    reset();
}

template<size_t N>
BufferObjects<N>::~BufferObjects()
{
    if (valid) {
        glDeleteBuffers(N, buffer.data());
    }
}

template<size_t N>
BufferObjects<N>::BufferObjects(BufferObjects<N>&& from) noexcept
{
    // Move the resources from the other object.
    std::move(std::begin(from.buffer), std::end(from.buffer), std::begin(buffer));

    // Maintain the correct valid states
    // The rhs is no longer in a valid state and has no resources.
    valid = from.valid;
    from.valid = false;
}

template<size_t N>
BufferObjects<N>& BufferObjects<N>::operator=(BufferObjects<N>&& from)
    noexcept
{
    // The standard copy and swap not efficient.
    // So we should do a test for self assignment
    if (this != &from)
    {
        // Destroy then re-create this object.
        // Call destructor and then placement new to use
        // the move copy constructor code to set this value.
        ~BufferObjects();
        new (this) BufferObjects(std::move(from));
    }
    return *this;
}

template<size_t N>
void BufferObjects::reset()
{
    if (!valid) {
        glGenBuffers(N, buffer.data());
        valid = true;
    }
}