簡體   English   中英

在堆上創建對象,並通過程序其余部分中的指針容器進行訪問

[英]Creating objects on the heap and accessing via containers of pointers in rest of program

我一直很難從成員變量的角度理解共享指針的工作方式。 SO上有很多很好的問題,它們解釋了共享指針以及如何/何時使用它們( thisthisthis ,等等)。 但是,我一直在努力理解它們在處理類實例變量時的工作方式,尤其是那些作為容器的變量(如std::vector )。

我的工作流程涉及

  1. 從文件讀取數據
  2. 將數據存儲在類中的容器中
  3. 在包含類的實例中訪問,修改和傳遞數據

我試圖了解我的代碼是否(和在哪里)進行了不必要的復制,或者我傳遞的常量引用是否足夠好。 閱讀后,我傾向於認為我應該在堆上一次創建對象,並在周圍傳遞共享的指針而不是常量引用,但是我無法闡明原因。

我將程序的某些部分粘貼(大致)在當前的實現中。 我的問題是:

  • 對於PointCloud類,我應該替代地存儲共享指針Point3D對象在_data矢量? 以此方式,濾波操作過程中,我可以填充我_inliers_outliers通過填充它們各自的點雲變量_data與共享指針成員變量到適當的三維點對象?
  • 對於Scene類和Filter類,使PointCloud類型成員變量共享指向PointCloud指針PointCloud嗎? 我可以肯定我當前的getter實現會返回副本,並且這些PointCloud對象可以包含數百萬個Point3D對象,因此它們並不小。 這比返回常量引用PointCloud::getData() (就像我在PointCloud::getData()所做的PointCloud::getData()

最終,我認為問題的根源可以歸結為: 我應該在堆上幾乎完成所有Point3D對象創建並將共享指針存儲在容器類成員變量中嗎? 本質上,這將使用一種“共享內存”模型。 如果是這樣,效率提高會是什么? 如果沒有,為什么不呢?


這是我程序的一些組件。

(注意:實際上,實際上並不是所有內聯的實現。為了簡潔起見,我只是在這里這樣做)。

scene.h

#include "pointcloud.h"
#include "point3D.h" // just defines the Point3D class

class Scene
{
    private:
        // Other member variables...

        /** Pointcloud */
        PointCloud _pointcloud;

    public:
        // ...Public functions...

        inline PointCloud getPointCloud() const; // Return point cloud
        inline void readPoints3D(const std::string &path_to_file);
};

PointCloud Scene::getPointCloud() const { return _pointcloud; }

void Scene::readPoints3D(const std::string &path_to_file)
{
    std::ifstream file(path_to_file.c_str());

    // Run through each line of the text file
    std::string line;
    std::string item;
    while (std::getline(file, line))
    {
        // Initialize variables id, x, y, z, r, g, b from file data

        Point3D pt(id, x, y, z, r, g, b); // Create Point3D object

        _pointcloud.addPoint(pt); // Add point to pointcloud
    }
    file.close();
}

點雲

#include "point3D.h"

#include <vector>

class PointCloud
{
    private:
        /** PointCloud data */
        std::vector<Point3D> _data;

    public:
        // Public member functions
        inline std::vector<Point3D> & getData();
        inline const std::vector<Point3D> & getData() const;
        inline void addPoint(const Point3D &pt);
};

const std::vector<Point3D> & PointCloud::getData() const { return _data; }

std::vector<Point3D> & PointCloud::getData() { return _data; }

void PointCloud::addPoint(const Reprojection::Point3D &pt)
{
    _data.push_back(pt); // Add the point to the data vector
}

過濾器

#include "pointcloud.h"

// Removes 3D points from a pointcloud if they don't meet certain conditions
class Filter
{
    private:

        // Good points that should stay in the pointcloud
        PointCloud _inliers;

        // Removed points
        PointCloud _outliers;

    public:
        Filter(const PointCloud &pointcloud) // Constructor

        void filterPointCloud(); // Filtering operation

        inline PointCloud getInliers();
        inline PointCloud getOutliers();
}

Filter::Filter(const PointCloud &pointcloud) :
    _inliers(pointcloud), _outliers(PointCloud()) {}

PointCloud getInliers() { return _inliers; }
PointCloud getOutliers() { return _outliers; }

驅動程序

#include "scene.h"
#include "pointcloud.h"
#include "filter.h"

// Some function that writes my pointcloud to file
void writeToFile(PointCloud &cloud);

int main()
{
    Scene scene;

    scene.readPoints3D("points3D_file.txt");

    PointCloud cloud = scene.getPointCloud();

    Filter f(cloud);
    f.filterPointCloud();

    writeToFile(f.getInliers());
    writeToFile(f.getOutlier());
}

當您遇到一生的問題時,可以得到的建議之一是“ use shared_ptr ”。 采納該建議后,您將遇到兩個問題。

首先,您現在正在使用shared_ptr ,因此請使用它來表達您的生命周期問題。 而且您仍然遇到最初的終身問題。

shared_ptr表示以下概念:特定數據位的生存期應該是所有shared_ptr的生存期與該數據位的並集。 這是對對象生命周期的復雜描述。

有時您實際上需要一個復雜的對象生存期描述。 在其他時候,您不需要。

使代碼盡可能簡單,當不需要復雜的對象生命期時,請勿使用指針。

如果您的代碼簡單且功能純凈,則幾乎不需要指針。 如果您處於糾纏狀態,則可能需要使用指針,但是避免糾纏狀態是比使指針和生命周期管理變得極其復雜的更好的解決方案。

盡可能使用值; 值很簡單,易於推理,並且可以縮放。 盡可能避免使用對系統有意義的對象標識(即,其內存位置)。

有充分的理由使用shared_ptr ,但是簡單地“在堆上分配所有內容並使用shared_ptr而不用擔心對象的生存時間”會導致無法維持的狀態依賴狀態,泄漏,崩潰,組件之間的隨機隱藏依賴關系,無法預測的對象生存期,以及由於緩存不一致性而導致的糟糕表現。

大型垃圾收集系統仍然存在嚴重和復雜的對象生命周期問題以及嚴重的局部性問題。 而且shared_ptr不是完整的垃圾回收系統。

一切都取決於對象的生命周期以及由誰來控制它們。 std::shared_ptr在於它會自動為您處理; 當對象的最后一個shared_ptr被銷毀時,對象本身也將被銷毀。 只要對象的shared_ptr存在,它仍然有效。

引用(常量或不常量)不具有該保證。 生成對超出范圍的對象的引用非常容易。 但是,如果可以通過其他方式保證對象生存期將超過引用的生存期,則引用比shared_ptr更靈活,更高效。

可以保證對象壽命的一個地方是調用對象作為參數的函數時。 該對象將一直存在,直到函數結束,除非該函數試圖做一些瘋狂的事情,例如delete它。 唯一需要使用shared_ptr作為參數的時間是在函數嘗試保存指針供以后使用時。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM