根据我最近在一次面试中的建议,有人建议我研究C++11的unique_ptr功能,作为自动垃圾收集的一种手段。因此,我使用了一个旧项目,并用unique_ptrs替换了指向用"new"关键字创建的对象的原始指针。然而,我认为我已经遇到了所有权的问题。
在我的mainclass.cpp(发布在下面)中,请将注意力转向init函数和我创建的新实例化对象的3个unique_ptrs。命名为"bg"、"bg2"one_answers"theGrid"。(下面注释掉的声明是它们过去的操作方式,切换回这种方法,程序运行得很好。)
但是,使用unique_ptrs,函数void display()中的行:
theGrid->doGridCalculations();//MODEL
生成访问冲突。这也是序列中第一次取消引用任何指向的对象,这让我相信unique_ptr的所有权已经在某个地方丢失了。然而,unique_ptr本身从未被传递到另一个函数或容器中,而是保留在mainclass.cpp的范围内,因此我没有看到使用std::move(theGrid)将所有权转移到需要的地方的机会。
主类.cpp:
#include <stdio.h>
#include <GL/glut.h>
#include <math.h>
#include "Block.h"
#include "dStructs.h"
#include "Grid.h"
#include "Texture.h"
#include "freetype.h"
#include <Windows.h>
//////////////////////////////////////////////////////
///Declare a couple of textures - for the background
//////////////////////////////////////////
Texture* bg;
Texture* bg2;
//and theGrid
Grid* theGrid;
/////////////////////////////////////////////////
///Declare our font
/////////////////////////////////////////////////
freetype::font_data scoreFont;
/////////////////////////////////////////////////////////
//Initialize the variables
///////////////////////////////////////////////////////
typedef dStructs::point point;
const int XSize = 755, YSize = 600;
point offset = {333,145};
point mousePos = {0,0};
void init(void)
{
//printf("n......Hello Guy. n....nInitilising");
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0,XSize,0,YSize);
//////////////////////////
//initialise the fonts
/////////////////////////
try{
scoreFont.init("Visitor TT2 BRK Regular.ttf", 20);
} catch (std::exception &e) {
MessageBox(NULL, e.what(), "EXCEPTION CAUGHT", MB_OK | MB_ICONINFORMATION);
}
///////////////////////////////////////////////////////////////
///bg new MEMORY MANAGED EDITION
//////////////////////////////////////////////////////////////////
unique_ptr<Texture> bg(new Texture(1024,1024,"BackGround.png"));
unique_ptr<Texture> bg2(new Texture(1024,1024,"BackGround2.png"));
unique_ptr<Grid> theGrid(new Grid(offset));
/////////////////////////////////////////////////
/// Old bad-memory-management style of pointed objects
/////////////////////////////////////////////////
//bg = new Texture(1024,1024,"BackGround.png");
//bg2 = new Texture(1024,1024,"BackGround2.png");
//theGrid = new Grid(offset);
glClearColor(0,0.4,0.7,1);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);//activate the alpha blending functionality
glEnable(GL_BLEND);
glLineWidth(2); // Width of the drawing line
glMatrixMode(GL_MODELVIEW);
glDisable(GL_DEPTH_TEST);
//printf("nInitialisation Complete");
}
void myPassiveMouse(int x, int y)
{
//Stupid OGL coordinate system
y = YSize - y;
mousePos.x = x;
mousePos.y = y;
printf("nthe mouse coordinates are (%f,%f)",mousePos.x, mousePos.y);
}
void displayGameplayHUD()
{
///////////////////////////////
//SCORE
//////////////////////////////
glColor4f(0.7f,0.0f,0.0f,7.0f);//set the colour of the text
freetype::print(scoreFont, 100,400,"SCORE: ");
glColor4f(1.0f,1.0f,1.0f,1.0f);//Default texture colour. Makes text white, and all other texture's as theyre meant to be.
}
//////////////////////////////////////////////////////
void display()
{
////printf("nBeginning Display");
glClear(GL_COLOR_BUFFER_BIT);//clear the colour buffer
glPushMatrix();
theGrid->doGridCalculations();//MODEL
point bgLoc = {XSize/2,YSize/2};
point bgSize = {XSize,YSize};
bg2->draw(bgLoc,bgSize);
theGrid->drawGrid();//DISPLAY
bg->draw(bgLoc,bgSize);
if(theGrid->gridState == Grid::STATIC)
{
theGrid->hoverOverBlocks(mousePos);//CONTROLLER
}
displayGameplayHUD();
glPopMatrix();
glFlush(); // Finish the drawing
glutSwapBuffers();
////printf("nFresh Display Loaded");
glutPostRedisplay();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv); // GLUT Initialization
glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE); // Initializing the Display mode
glutInitWindowSize(755,600); // Define the window size
glutCreateWindow("Gem Miners"); // Create the window, with caption.
init(); // All OpenGL initialization
//-- Callback functions ---------------------
glutDisplayFunc(display);
//glutKeyboardFunc(mykey);
//glutSpecialFunc(processSpecialKeys);
//glutSpecialUpFunc(processSpecialUpKeys);
glutMouseFunc(mymouse);
glutPassiveMotionFunc(myPassiveMouse);
glutMainLoop(); // Loop waiting for event
}
我认为所有权需要在某个时候转移,但我不知道在哪里。
提前感谢,Guy
这些是全局原始指针:
Texture* bg;
Texture* bg2;
//and theGrid
Grid* theGrid;
这些是完全不相关的unique_ptr
,是init函数的本地。
unique_ptr<Texture> bg(new Texture(1024,1024,"BackGround.png"));
unique_ptr<Texture> bg2(new Texture(1024,1024,"BackGround2.png"));
unique_ptr<Grid> theGrid(new Grid(offset));
当unique_ptr
超出范围时,它们将被销毁。它们指向的对象也会被销毁,因为unique_ptr
在其析构函数中就是这样做的。在这一过程中,任何时候都没有涉及这场灾难的全球原始指针。它们被同名的本地unique_ptr
隐藏。
您应该将全局原始指针更改为unique_ptr
s。然后您可以在init函数中设置它们(不要重新声明它们),如下所示:
bg.reset(new Texture(1024,1024,"BackGround.png"));
bg2.reset(new Texture(1024,1024,"BackGround2.png"));
theGrid.reset(new Grid(offset));
您在init
函数中创建的唯一指针不会修改在文件范围内声明的指针,文件范围内的指针默认初始化为0或nullptr
(我不太熟悉C++11,所以我不确定是哪一个)。
您在init
函数中所做的是创建三个新的对象,它们的名称覆盖文件范围内的对象,因此当您使用文件范围外的对象时,您会遇到访问冲突,因为它们从未设置为指向任何有效对象。
init
中的unique_ptr<Grid>
是该函数的本地函数。unique_ptr<Grid>
将在函数结束时超出作用域,破坏自身及其拥有的Grid
。看起来你想要一个全局对象unique_ptr<Grid> theGrid;
来代替你现在拥有的Grid* theGrid;
。然后在init
中,您可以执行以下操作:
theGrid.reset(new Grid(offset));
在display
中被访问的theGrid
是类型为Grid*
的全局theGrid
。
您尝试创建的其他unique_ptr
也是如此。
当然,与全局对象相比,传递这些对象要好得多,但使用GLUT会让这有点痛苦。