c – shared_ptr,unique_ptr,所有权,在这种特殊情况下我是否过度了?

前端之家收集整理的这篇文章主要介绍了c – shared_ptr,unique_ptr,所有权,在这种特殊情况下我是否过度了?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我从事图形应用程序,并一直在使用共享和唯一的指针本质上是因为它为我处理内存释放(也称为方便),这可能是坏的(如果这就是我使用它们的原因).

我最近读到了关于Stackoverflow问题的答案,提到根据B. Stroustrup,通常不应该使用唯一/共享ptrs,而且应该通过值传递参数.

我有一个图形的情况,我认为使用shared_ptr是有道理的,但我想知道专家(我不是C专家),如果我过度做/思考它,如果是这样,他们会做什么(为了符合C建议和效率)

我将解决渲染/光线跟踪中出现的一般问题.在这个特殊的问题中,我们有一个对象池(我们将使用三角形进行此解释)和一个结构,为了简化说明,我们将其称为常规3D网格.让我们说在某些时候我们需要将三角形插入到网格中:这意味着我们需要检查每个插入三角形的边界体积是否与网格中的任何单元格重叠,然后是每个重叠的单元格需要保持指向该三角形的指针/引用(供以后使用).一个三角形可能会重叠超过1个单元格,因此它可以被多个单元格引用多次(您可以在这里看到我使用shared_ptr的位置).

请注意,在网格结构之外,我们不需要三角形池(因此从技术上讲,拥有三角形池的对象是网格,或者更确切地说是网格的单元格).

class Grid
{
    struct Cell
    {
        std::vector<std::shared_ptr<const Triangle>> triList; 
    };
    void insert(triangle*& tri_)
    {
        std::shared_ptr<const Triangle> tri = tri_;
        for (each cell overlapped by tri) {
            // compute cell index
            uint32_t i = ...
            cells[i].triList.push_back(tri);
        }
    }
    Cell cells[RES * RES * RES];
};

void createPoolOfTrianglesAndInsertIntoGrid()
{
    Grid grid;
    uint32_t maxTris = 32;
    Triangle* tris = new Triangles[maxTris];
    // process the triangles
    ...
    // now insert into grid
    for (uint32_t i = 0; i < maxTris; ++i) {
        // use placement new
        Triangle* tri = new (&tris[i]) Triangle;
        grid.insert(tri);
    }
    // no need to delete tris here ... it should be done by 
    // the grid when we go out of this function's scope
}

这听起来很复杂,但我的设计背后的动机是遵循Stroustrup的建议.在这种情况下,函数createPoolOfTrianglesAndInsertIntoGrid不拥有三角形,它是网格的单元格.所以我在函数createPoolOfTrianglesAndInsertIntoGrid中分配内存,因为这是我需要创建三角形的地方,然后我使用placement new方法获取指向该池中每个三角形的指针,然后我可以将其传递给网格插入方法(I将该对象的内存管理推迟到该方法).在那里,它将三角形转换为shared_ptr,并且单元格现在可以共享它的“引用”(使用shared_ptr).

我想知道你是否认为这是正确的方向,或者如果这看起来完全错误,无论是在实施方面还是在可能的效率损失方面(我分配了一个内存池,然后使用新的位置来创建一个临时三角形,然后我将其传递给网格插入方法,然后转换为shared_ptr,…)

我正在努力学习和改进我的代码,并希望您能提供有价值的专业反馈.

编辑:基本上我试图找到正确的方法解决这个问题,我会根据你的评论稍后提供一些修改

解决方法

在我看来,你的Grid拥有三角形.我假设三角形相对较轻(3-5维?).

我认为这样的事情可能适合.我在Grid中使用一个容器来按值取得三角形的所有权.当Grid超出范围时,容器将删除三角形.

然后每个Cell只使用原始指针来跟踪它引用的三角形. Cells不拥有三角形,只是保持指向Grid所拥有的三角形的指针.

class Grid
{
    struct Cell
    {
        std::vector<Triangle*> triList; // non owning
    };

    void insert(Triangle tri) // pass by value
    {
        tris.push_back(tri); // Grid owns this by value

        for(each cell overlapped by tri) {
            // compute cell index
            uint32_t i = ...

            cells[i].triList.push_back(&tris.back());
        }
    }

    // Use a deque because it won't re-allocate when adding
    // new elements to the end
    std::deque<Triangle> tris; // elements owned by value

   Cell cells[RES * RES * RES]; // point to owned elements
};

void createPoolOfTrianglesAndInsertIntoGrid()
{
    Grid grid; // owns the triangles (by value)

    uint32_t maxTris = 32;

    std::vector<Triangle> tris(maxTris);
    // process the triangles
    // ...
    // now insert into grid
    for(auto tri: tris)
        grid.insert(tri);
    }

    // no need to delete tris here ... it should be done by
    // the grid when we go out of this function's scope
}

注意:我使用std :: deque在Grid中按值存储三角形.那是因为在添加新三角形时它不会重新分配其内部存储器.如果你在这里使用了std :: vector,你的原始指针最终会在std :: vector调整自身时悬空.

或者:

鉴于你看起来在你的函数中构建了所有三角形,然后将它们全部传递给Grid,为什么一次一个呢?你可以一次性通过整个容器.如果你使用移动语义这样做,你甚至不需要复制任何东西:

class Grid
{
    struct Cell
    {
        std::vector<Triangle*> triList; // non owning
    };

    // Accept the entire container in-tack
    // (no reallocations allowed after this point)
    void insert(std::vector<Triangle> tris) // pass by value (able to move in)
    {
        //
        for(auto& tri: tris)
        {
            for(each cell overlapped by tri) {
                // compute cell index
                uint32_t i = ...

                cells[i].triList.push_back(&tri);
            }
        }
    }

    // Using a vector so it MUST NOT be resized after
    // Cells have been pointed to its elements!!!
    std::vector<Triangle> tris; // elements owned by value
    Cell cells[RES * RES * RES]; // point to owned elements
};

void createPoolOfTrianglesAndInsertIntoGrid()
{
    Grid grid; // owns the triangles (by value)

    uint32_t maxTris = 32;

    // Build the triangles into
    std::vector<Triangle> tris(maxTris);
    // process the triangles
    // ...
    // now insert into grid
    grid.insert(std::move(tris)); // move the whole darn container (very efficient)

    // no need to delete tris here ... it should be done by
    // the grid when we go out of this function's scope
}

注意:现在我使用了std :: vector,因为你没有在到达Grid之后逐个添加三角形.但是你必须确保在Grid内部拥有的`std :: vector没有调整大小.

猜你在找的C&C++相关文章