簡體   English   中英

C++ 中的 2D 網格 class 實現

[英]2D mesh class implementation in C++

我想實現一個二維網格 class ,它是 memory 高效的,因為它將用於蒙特卡羅模擬。 然而,在這個階段,這實際上與二維數組 class 相同。 不用說,我是 C++ 的新手。 我已經編寫了以下代碼。

#define MESH2D_H_INCLUDED

class Mesh2D
{
private:

    double* mesh;
    size_t  rows;
    size_t  columns;

public:

    /* constructor */
    Mesh2D(size_t Nx, size_t Ny){
        rows    = Nx;
        columns = Ny;
        mesh    = new double[Nx*Ny] {};
        std::cout << "Mesh created." << std::endl;
    }

    /* destructor */
    ~Mesh2D()
    {
        delete[] mesh;
        std::cout << "Mesh deleted." << std::endl;
    }

    /* accessors */
    double getrows() const {return rows;}
    double getcolumns() const {return columns;}
    double& operator()(size_t i, size_t j)
    {
        if (i > rows || j > columns){
            throw std::out_of_range("Index exceeds array bounds.");
        }
        return mesh[j + i*columns]; // row major access
    }

    /* copy constructor */
    Mesh2D& operator=(const Mesh2D& rhs) // what is the difference between this line and the following? inline operator=(const Mesh2D& rhs)
    {
        if (rhs.rows != rows || rhs.columns != columns){
            throw std::out_of_range("Assignment cannot be performed, mesh dimensions do not agree.");
        }
        mesh = new double [rows*columns];

//        I want to avoid using a for loop
//        for (int i=0; i<rows*columns; i++){
//            mesh[i] = rhs.mesh[i];
//        }
//      Use this instead
        memcpy(mesh, rhs.mesh, sizeof(rhs)); //however the output is not the expected.
        std::cout << "copied!" << std::endl;
    }

};

#endif // MESH2D_H_INCLUDED
//MAIN FUNCTION

#include <iostream>
#include "Mesh2D.h"

void PrintMesh2D(Mesh2D &mesh){ //why isn't it going to work if I add const? I mean: void PrintMesh2D(const Mesh2D &mesh)

    for (int i=0; i<mesh.getrows(); i++){

        for (int j=0; j<mesh.getcolumns(); j++){

            std::cout << mesh(i,j) << " ";
        }
        std::cout << std::endl;
    }
}

int main()
{

    Mesh2D mesh{3,3};
    Mesh2D newmesh{3,3};

    for (int i=0; i<mesh.getrows(); i++){
        for (int j=0; j<mesh.getcolumns(); j++){
            mesh(i,j) = j + i * mesh.getcolumns();
        }
    }

    newmesh = mesh;
    PrintMesh2D(newmesh);

}

控制台輸出

我的問題被寫成評論,但我也在這里列出:

  1. 在復制構造函數內部,這行Mesh2D& operator=(const Mesh2D& rhs)和這一行inline operator=(const Mesh2D& rhs)什么區別?

  2. 同樣,在復制構造函數中,我想避免 for 循環並改用 memcpy。 但是,output 不是預期的,我做錯了什么?

  3. 里面的主要 function:為什么這不會編譯? void PrintMesh2D(const Mesh2D &mesh)

  4. 最后,實現是否完成? 我的意思是,是否缺少任何重要的特性/功能?

歡迎您給我任何建議。 由於我是 C++ 的新手,我覺得我正在編寫錯誤的錯誤代碼。

編輯:

我寫了以下作為復制構造函數。

/* copy constructor */
    Mesh2D (const Mesh2D& rhs)
    {
        rows    = rhs.rows;
        columns = rhs.columns;
        mesh    = new double[rows*columns];
        memcpy(mesh,rhs.mesh,rows*columns*sizeof(double));
        std::cout << "Copied!" << std::endl;
    } 

看起來對嗎?

  1. inline operator=(const Mesh2D& rhs)是一個語法錯誤,它錯過了返回類型。 此外Mesh2D& operator=(const Mesh2D& rhs)是復制賦值運算符,而不是復制構造函數,即Mesh2D(const Mesh2D& rhs)
  2. 您可以使用memcpy ,但最后一個參數應該是正確的大小rows*colums*sizeof(double) sizeof(rhs)是 class object 的大小,與數組大小無關。 由於您在復制賦值運算符中而不是在復制構造函數中,因此已經分配了mesh的 memory,因此您應該刪除mesh = new double [rows*columns]; 來自復制賦值運算符。 您還必須return *this; 在那里匹配返回類型。
  3. 因為那時您需要仿函數的const版本: double operator()(size_t i, size_t j) const
  4. 閱讀規則 3 或規則 5,如果您有構造函數和析構函數,則應該實現復制構造函數。
  5. 來自@PaulMcKenzie:使用 std::vector 不必執行 1、2 或 4。

這是一個完整的例子: https://ideone.com/seOSwN

我將嘗試將缺少的部分添加到您的代碼中:

  1. 復制構造函數

  2. 工作分配運算符。

在下面的代碼之后,我將評論:

#include <iostream>
#include <cstring>
#include <algorithm>

class Mesh2D
{
    private:
    size_t  rows;
    size_t  columns;
    double* mesh;

public:

    Mesh2D(size_t Nx, size_t Ny) : rows(Nx), columns(Ny), mesh(new double[Nx*Ny]{})
    {
        std::cout << "Mesh created." << std::endl;
    }

    Mesh2D(const Mesh2D& rhs) : rows(rhs.rows), columns(rhs.columns), 
                                mesh(new double[rhs.rows * rhs.columns])
    {
       memcpy(mesh, rhs.mesh, (rhs.rows * rhs.columns) * sizeof(double));

       // or better yet
       // std::copy(rhs.mesh, rhs.mesh + rhs.rows * rhs.columns, mesh);
    }
    
    Mesh2D& operator=(const Mesh2D& rhs)
    {
       if ( &rhs != this )
       {
          Mesh2D temp(rhs);
          std::swap(temp.rows, rows);
          std::swap(temp.columns, columns);
          std::swap(temp.mesh, mesh);
      }
      return *this;
    }
       
    ~Mesh2D()
    {
        delete[] mesh;
        std::cout << "Mesh deleted." << std::endl;
    }


    double getrows() const {return rows;}
    double getcolumns() const {return columns;}

    double& operator()(size_t i, size_t j)
    {
        if (i > rows || j > columns){
            throw std::out_of_range("Index exceeds array bounds.");
        }
        return mesh[j + i*columns]; // row major access
    }

    double& operator()(size_t i, size_t j) const
    {  
        if (i > rows || j > columns){
            throw std::out_of_range("Index exceeds array bounds.");
        }
        return mesh[j + i*columns]; // row major access
    }
};

首先,注意使用成員初始化列表來初始化Mesh2D class的成員。 以這種方式做事是一個好習慣,而不是在構造函數的主體內分配。


其次,注意賦值運算符。 它使用復制/交換習慣來安全、干凈地釋放舊的 memory 並進行復制。


第三, operator()應該有一個const重載,否則你永遠不能像這樣使用你的 class :

void foo(const Mesh2D& m)
{
   std::cout << m(0,0);
}

原因是m是一個const引用,因此您只能在其上調用const函數。 因此, operator()需要一個const版本以及非常量版本。

此外,非常量版本的operator()也需要存在的原因是您可能想要這樣做:

void foo2(Mesh2D& m)
{
   m(0,0) = 23;
}

如果m只有一個const版本的operator() ,則由於operator()更改了 object 的內部 state,因此無法完成上述操作。


另一個問題是您錯誤地使用memcpy memcpy適用於字節數,而不是數組中的項目數。 因此,您需要乘以sizeof(double) ,因為這是您要復制的字節數。 一個更安全的解決方案是使用std::copy ,它使用項目數自動使用正確的復制 function 。


最后,已從賦值運算符中刪除了對錯誤“Mesh2D”的測試。 原因是賦值運算符(和復制構造函數)工作是一回事,而且只有一件事——制作副本。

當您開始將業務邏輯引入到復制分配函數中時,您將冒着制作不是副本的風險,而是制作正在傳入的 object 的偽副本。

這會導致 C++ 中的一些最討厭和最難發現的錯誤,這就是您的復制分配函數想要玩游戲而不是真正復制的時候。 如果您的復制構造函數或賦值運算符根據傳入的值做出太多決策並執行邏輯,您就會知道什么時候做錯了。


為了完成,這里是 class 的相同版本,但使用std::vector<double> 請注意,由於不需要用戶定義的賦值運算符、復制構造函數或析構函數,代碼要小得多:

#include <iostream>
#include <vector>

class Mesh2D
{
    private:
    size_t  rows;
    size_t  columns;
    std::vector<double> mesh;

public:

    Mesh2D(size_t Nx, size_t Ny) : rows(Nx), columns(Ny), mesh(Nx*Ny)
    {
        std::cout << "Mesh created." << std::endl;
    }

    double getrows() const {return rows;}
    double getcolumns() const {return columns;}

    double& operator()(size_t i, size_t j)
    {
        if (i > rows || j > columns){
            throw std::out_of_range("Index exceeds array bounds.");
        }
        return mesh[j + i*columns]; 
    }

    const double& operator()(size_t i, size_t j) const
    {  
        if (i > rows || j > columns)    {
            throw std::out_of_range("Index exceeds array bounds.");
        }
        return mesh[j + i*columns]; 
    }
};

暫無
暫無

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

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