opengl
ओपन ++ ऑब्जेक्ट्स को C ++ RAII के साथ एनकैप्सुलेट करना
खोज…
परिचय
OpenGL ऑब्जेक्ट्स के विभिन्न तरीकों के उदाहरण C ++ RAII के साथ काम करते हैं।
टिप्पणियों
OpenGL ऑब्जेक्ट्स के RAII एनकैप्सुलेशन के खतरे हैं। सबसे अपरिहार्य है कि OpenGL ऑब्जेक्ट OpenGL संदर्भ के साथ जुड़े हुए हैं जिसने उन्हें बनाया है। तो C ++ RAII ऑब्जेक्ट का विनाश एक OpenGL संदर्भ में किया जाना चाहिए, जो उस C ++ ऑब्जेक्ट द्वारा प्रबंधित OpenGL ऑब्जेक्ट के स्वामित्व को साझा करता है।
इसका अर्थ यह भी है कि यदि सभी संदर्भ जो वस्तु के मालिक हैं, नष्ट हो जाते हैं, तो किसी भी मौजूदा RAII ने OpenGL ऑब्जेक्ट को ऑब्जेक्ट में नष्ट करने का प्रयास किया है जो अब मौजूद नहीं है।
इस तरह के संदर्भ मुद्दों से निपटने के लिए आपको मैन्युअल कदम उठाने होंगे।
C ++ में 98/03
C ++ 98/03 में एक OpenGL ऑब्जेक्ट को एनकैप्सुलेट करना 3. C ++ नियम का पालन करना आवश्यक है। इसका मतलब है कि एक कॉपी कंस्ट्रक्टर, कॉपी असाइनमेंट ऑपरेटर और डिस्ट्रक्टर को जोड़ना।
हालांकि, कॉपी कंस्ट्रक्टर्स को तार्किक रूप से ऑब्जेक्ट को कॉपी करना चाहिए। और OpenGL ऑब्जेक्ट की प्रतिलिपि बनाना एक गैर-तुच्छ उपक्रम है। समान रूप से महत्वपूर्ण, यह लगभग निश्चित रूप से कुछ ऐसा है जो उपयोगकर्ता करने की इच्छा नहीं करता है।
इसलिए हम बदले में वस्तु को गैर-प्रतिलिपि बनाएंगे:
class BufferObject
{
public:
BufferObject(GLenum target, GLsizeiptr size, const void *data, GLenum usage)
{
glGenBuffers(1, &object_);
glBindBuffer(target, object_);
glBufferData(target, size, data, usage);
glBindBuffer(target, 0);
}
~BufferObject()
{
glDeleteBuffers(1, &object_);
}
//Accessors and manipulators
void Bind(GLenum target) const {glBindBuffer(target, object_);}
GLuint GetObject() const {return object_;}
private:
GLuint object_;
//Prototypes, but no implementation.
BufferObject(const BufferObject &);
BufferObject &operator=(const BufferObject &);
};
कंस्ट्रक्टर ऑब्जेक्ट का निर्माण करेगा और बफर ऑब्जेक्ट के डेटा को इनिशियलाइज़ करेगा। संहारक वस्तु को नष्ट कर देगा। कॉपी कंस्ट्रक्टर / असाइनमेंट को परिभाषित किए बिना उन्हें घोषित करने से, लिंककर्ता एक त्रुटि देगा यदि कोई कोड उन्हें कॉल करने का प्रयास करता है। और उन्हें निजी घोषित करके, केवल BufferObject
सदस्य ही उन्हें कॉल कर पाएंगे।
ध्यान दें कि BufferObject
निर्माता को दिए गए target
बनाए नहीं रखता है। ऐसा इसलिए है क्योंकि OpenGL बफ़र ऑब्जेक्ट का उपयोग किसी भी लक्ष्य के साथ किया जा सकता है, न कि केवल उसी के साथ शुरू में बनाया गया था। यह बनावट की वस्तुओं के विपरीत है, जिसे हमेशा उस लक्ष्य के लिए बाध्य होना चाहिए जिसे वे शुरू में बनाए गए थे।
क्योंकि ओपनजीएल विभिन्न उद्देश्यों के लिए संदर्भ के लिए वस्तुओं को बांधने पर बहुत निर्भर है, इसलिए अक्सर रॉ-स्टाइल स्कोप्ड ऑब्जेक्ट को भी बाध्यकारी होना उपयोगी होता है। क्योंकि अलग-अलग वस्तुओं की अलग-अलग बाध्यकारी ज़रूरतें होती हैं (कुछ में लक्ष्य होते हैं, अन्य में नहीं होते हैं), हमें प्रत्येक वस्तु के लिए व्यक्तिगत रूप से एक को लागू करना होगा।
class BindBuffer
{
public:
BindBuffer(GLenum target, const BufferObject &buff) : target_(target)
{
buff.Bind(target_);
}
~BindBuffer()
{
glBindBuffer(target_, 0);
}
private:
GLenum target_;
//Also non-copyable.
BindBuffer(const BindBuffer &);
BindBuffer &operator=(const BindBuffer &);
};
BindBuffer
गैर-प्रतिलिपि योग्य है, क्योंकि इसे कॉपी करने से कोई मतलब नहीं है। ध्यान दें कि यह BufferObject
तक पहुँच को बनाए नहीं रखता है, इसे बांधता है। वह इसलिए कि यह अनावश्यक है।
C ++ 11 और बाद में
C ++ 11 ऐसे उपकरण प्रदान करता है जो RAII-Encapsulated OpenGL ऑब्जेक्ट की कार्यक्षमता को बढ़ाते हैं। C ++ 11 की विशेषताओं के बिना, चालित शब्दार्थ की तरह, ऐसी वस्तुओं को गतिशील रूप से आवंटित करना होगा यदि आप उन्हें पास करना चाहते हैं, क्योंकि वे कॉपी नहीं किए जा सकते हैं। मूव सपोर्ट उन्हें सामान्य मानों की तरह आगे-पीछे करने की अनुमति देता है, हालाँकि कॉपी करके नहीं:
class BufferObject
{
public:
BufferObject(GLenum target, GLsizeiptr size, const void *data, GLenum usage)
{
glGenBuffers(1, &object_);
glBindBuffer(target, object_);
glBufferData(target, size, data, usage);
glBindBuffer(target, 0);
}
//Cannot be copied.
BufferObject(const BufferObject &) = delete;
BufferObject &operator=(const BufferObject &) = delete;
//Can be moved
BufferObject(BufferObject &&other) noexcept : object_(other.Release())
{}
//Self-assignment is OK with this implementation.
BufferObject &operator=(BufferObject &&other) noexcept
{
Reset(other.Release());
}
//Destroys the old buffer and claims ownership of a new buffer object.
//It's OK to call glDeleteBuffers on buffer object 0.
GLuint Reset(GLuint object = 0)
{
glDeleteBuffers(1, &object_);
object_ = object;
}
//Relinquishes ownership of the object without destroying it
GLuint Release()
{
GLuint ret = object_;
object_ = 0;
return ret;
}
~BufferObject()
{
Reset();
}
//Accessors and manipulators
void Bind(GLenum target) const {glBindBuffer(target, object_);}
GLuint GetObject() const {return object_;}
private:
GLuint object_;
};
इस तरह के एक समारोह से वापस आ सकते हैं:
BufferObject CreateStaticBuffer(GLsizeiptr byteSize) {return BufferObject(GL_ARRAY_BUFFER, byteSize, nullptr, GL_STATIC_DRAW);}
जो आपको उन्हें अपने स्वयं के स्टोर करने की अनुमति देता है (केवल स्पष्ट रूप से स्थानांतरित-केवल) प्रकार:
struct Mesh
{
public:
private:
//Default member initializer.
BufferObject buff_ = CreateStaticBuffer(someSize);
};
एक स्कोप्ड बाइंडर क्लास में गतिमान सिमेंटिक्स भी हो सकते हैं, इस प्रकार बाइंडर को फ़ंक्शंस से वापस करने की अनुमति मिलती है और सी ++ मानक लाइब्रेरी कंटेनरों में संग्रहीत किया जाता है:
class BindBuffer
{
public:
BindBuffer(GLenum target, const BufferObject &buff) : target_(target)
{
buff.Bind(target_);
}
//Non-copyable.
BindBuffer(const BindBuffer &) = delete;
BindBuffer &operator=(const BindBuffer &) = delete;
//Move-constructible.
BindBuffer(BindBuffer &&other) noexcept : target_(other.target_)
{
other.target_ = 0;
}
//Not move-assignable.
BindBuffer &operator=(BindBuffer &&) = delete;
~BindBuffer()
{
//Only unbind if not moved from.
if(target_)
glBindBuffer(target_, 0);
}
private:
GLenum target_;
};
ध्यान दें कि ऑब्जेक्ट रचनात्मक रूप से मूव है लेकिन मूव-असाइन करने योग्य नहीं है। इसके साथ विचार यह है कि एक स्कोप्ड बफर बाइंडिंग के रिबंडिंग को रोकना। एक बार जब यह सेट हो जाता है, केवल एक चीज जो इसे परेशान कर सकती है, उससे ले जाया जा रहा है।