Tất cả các thao tác đó sao chép đối tượng C++. Vì lớp của bạn không định nghĩa một hàm tạo bản sao, bạn sẽ nhận được hàm tạo bản sao được tạo bởi trình biên dịch. Điều này chỉ đơn giản là sao chép tất cả các thành viên của đối tượng.
xem xét ví dụ đầu tiên:
vector<BufferObject> bufVec;
{
BufferObject some_buffer;
//Initialize some_buffer;
bufVec.push_back(some_buffer);
}
bufVec.back(); //buffer doesn't work.
Khi bạn gọi push_back
, nó sao chép some_buffer
thành một BufferObject
trong vector
. Vì vậy, ngay trước khi chúng tôi thoát khỏi phạm vi đó, có hai đối tượng BufferObject
.
Nhưng đối tượng bộ đệm OpenGL nào mà chúng lưu trữ? Vâng, họ lưu trữ cùng một số. Sau khi tất cả, để C + +, chúng tôi chỉ cần sao chép một số nguyên. Vì vậy, cả hai đối tượng C++ lưu trữ cùng một giá trị số nguyên.
Khi chúng tôi thoát khỏi phạm vi đó, some_buffer
sẽ bị hủy. Do đó, nó sẽ gọi glDeleteBuffers
trên đối tượng OpenGL này. Nhưng đối tượng trong vectơ vẫn sẽ có bản sao riêng của tên đối tượng OpenGL đó. Trong đó có bị hủy.
Vì vậy, bạn không thể sử dụng nó nữa; do đó các lỗi.
Điều tương tự cũng xảy ra với chức năng InitBuffer
của bạn. buff
sẽ bị hủy sau khi được sao chép vào giá trị trả về, điều này làm cho đối tượng trả về vô giá trị.
Tất cả điều này là do vi phạm "Quy tắc 3/5" trong C++. Bạn đã tạo ra một destructor mà không tạo các nhà xây dựng bản sao/di chuyển/chuyển nhượng. Thật tồi tệ.
Để giải quyết vấn đề này, trình bao bọc đối tượng OpenGL của bạn phải là các loại chỉ di chuyển. Bạn nên xóa constructor sao chép và sao chép toán tử gán, và cung cấp các khoản tương đương di chuyển chính xác đến các chuyển-từ đối tượng để đối tượng 0:
class BufferObject
{
private:
GLuint buff_;
public:
BufferObject()
{
glGenBuffers(1, &buff_);
}
BufferObject(const BufferObject &) = delete;
BufferObject &operator=(const BufferObject &) = delete;
BufferObject(BufferObject &&other) : buff_(other.buff_)
{
other.buff_ = 0;
}
BufferObject &operator=(BufferObject &&other)
{
//ALWAYS check for self-assignment
if(this != &other)
{
Release();
buff_ = other.buff_;
other.buff_ = 0;
}
return *this;
}
~BufferObject() {Release();}
void Release();
{
if(buff_)
glDeleteBuffers(1, &buff_);
}
//Other members.
};
Có various other techniques để làm giấy gói RAII di chuyển chỉ dành cho đối tượng OpenGL.