【问题标题】:Ownership of my new Unique_ptrs?我的新 Unique_ptrs 的所有权?
【发布时间】:2013-01-20 07:50:26
【问题描述】:

根据我最近在一次工作面试中的建议,我被建议研究 C++11 的 unique_ptr 功能,作为自动垃圾收集的一种手段。所以我正在使用一个较旧的项目,并用 unique_ptrs 替换指向使用“new”关键字创建的对象的原始指针。但是,我认为我遇到了所有权问题。

在我的 mainclass.cpp(发布在下面)中,请注意我创建的 init 函数和 3 个 unique_ptrs 到新实例化的对象。命名为“bg”、“bg2”和“theGrid”。 (下面被注释掉的声明是他们以前的做法,切换回这个方法,程序运行得很好。)

但是,使用 unique_ptrs,函数 void display() 中的行:

theGrid->doGridCalculations();//MODEL

产生访问冲突。这也是序列中第一次取消引用任何指向的对象,这让我相信 unique_ptr 的所有权已经在某个地方丢失了。但是,unique_ptrs 本身永远不会传递到另一个函数或容器中,并且仍然在 mainclass.cpp 的范围内,因此我没有看到任何机会使用 std::move(theGrid) 来将所有权转移到它需要的地方成为。

Mainclass.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 
}

我认为所有权需要在某个时候转移,但我不知道在哪里。

提前致谢, 伙计

【问题讨论】:

  • 你知道bg bg2theGridinit() 中初始化是该函数的本地函数吗?
  • unique_ptr 与垃圾收集完全不同。您仍然需要管理 unique_ptr 对象的生命周期;当对象超出范围时,您会自动删除,但这不是垃圾收集。 shared_ptr 更接近了,但仍然不一样;如果您有两个对象,每个对象都持有一个shared_ptr,那么它们将永远不会被销毁;垃圾收集器会摆脱它们。

标签: c++ smart-pointers unique-ptr ownership-semantics


【解决方案1】:

这些是全局原始指针:

Texture* bg;
Texture* bg2;
//and theGrid
Grid* theGrid;

这些是完全不相关的unique_ptrs,是 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_ptrs 超出范围时,它们将被销毁。它们指向的对象也会被销毁,因为这就是 unique_ptr 在其析构函数中所做的。在该过程中,没有任何时候涉及崩溃的全局原始指针。他们被本地的同名unique_ptrs 隐藏了。

您应该将全局原始指针更改为unique_ptrs。然后你可以像这样在 init 函数中设置它们(不要重新声明它们):

bg.reset(new Texture(1024,1024,"BackGround.png"));
bg2.reset(new Texture(1024,1024,"BackGround2.png"));
theGrid.reset(new Grid(offset));

【讨论】:

  • 谢谢,这就像以前一样工作,现在我对原始 ptr 和整个 unique_ptr 功能之间的所有权和差异有了更深入的了解。
【解决方案2】:

您在 init 函数中创建的唯一指针不会修改在文件范围内声明的指针,文件范围内的指针默认初始化为 0 或 nullptr(我不太精通 C ++11 所以我不确定是哪个)。

您在 init 函数中所做的是创建三个 new 对象,其名称​​shadow 文件范围内的对象,因此当您使用文件范围内的那些你会遇到访问冲突,因为它们永远不会指向任何有效的东西。

【讨论】:

    【解决方案3】:

    init 中的 unique_ptr&lt;Grid&gt; 是该函数的本地函数。 unique_ptr&lt;Grid&gt; 将在函数结束时超出范围,破坏自身和它拥有的 Grid。似乎您实际上想要一个全局对象 unique_ptr&lt;Grid&gt; theGrid; 来替换您目前拥有的 Grid* theGrid;。然后在init 你可以这样做:

    theGrid.reset(new Grid(offset));
    

    display 中访问的theGridGrid* 类型的全局theGrid

    对于您尝试创建的其他 unique_ptrs,情况完全相同。

    当然,与全局对象相比,传递这些对象会更好,但是您使用 GLUT 会让这有点痛苦。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-12
      • 2013-09-15
      • 2012-02-03
      • 1970-01-01
      • 2011-04-22
      相关资源
      最近更新 更多