繁体   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