简体   繁体   English

C++ 中的 2D 网格 class 实现

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

I want to implement a 2D mesh class which is memory efficient, since it will be used in a Monte Carlo simulation.我想实现一个二维网格 class ,它是 memory 高效的,因为它将用于蒙特卡罗模拟。 At this stage however, this is actually the same as a 2D array class.然而,在这个阶段,这实际上与二维数组 class 相同。 Needless to say, I am new to C++.不用说,我是 C++ 的新手。 I have written the following code.我已经编写了以下代码。

#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);

}

控制台输出

My questions are written as comments but I am listing them here as well:我的问题被写成评论,但我也在这里列出:

  1. Inside the copy constructor, what is the difference between this line Mesh2D& operator=(const Mesh2D& rhs) and this line inline operator=(const Mesh2D& rhs) ?在复制构造函数内部,这行Mesh2D& operator=(const Mesh2D& rhs)和这一行inline operator=(const Mesh2D& rhs)什么区别?

  2. Again, inside the copy constructor I would like to avoid a for loop and use memcpy instead.同样,在复制构造函数中,我想避免 for 循环并改用 memcpy。 However, the output is not the expected, what am I doing wrong?但是,output 不是预期的,我做错了什么?

  3. Inside the main function: Why is this not going to compile?里面的主要 function:为什么这不会编译? void PrintMesh2D(const Mesh2D &mesh)

  4. Finally, is the implementation complete?最后,实现是否完成? I mean, are there any important features/functions that are missing?我的意思是,是否缺少任何重要的特性/功能?

You are welcome to give me any piece of advice.欢迎您给我任何建议。 Since I am new to C++, I have the feeling that I am writing bad buggy code.由于我是 C++ 的新手,我觉得我正在编写错误的错误代码。

EDIT:编辑:

I wrote the following as a copy constructor.我写了以下作为复制构造函数。

/* 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;
    } 

Looks right?看起来对吗?

  1. inline operator=(const Mesh2D& rhs) is a syntax error, it misses the return type. inline operator=(const Mesh2D& rhs)是一个语法错误,它错过了返回类型。 Also Mesh2D& operator=(const Mesh2D& rhs) is the copy assignment operator, not the copy constructor, that would be Mesh2D(const Mesh2D& rhs) .此外Mesh2D& operator=(const Mesh2D& rhs)是复制赋值运算符,而不是复制构造函数,即Mesh2D(const Mesh2D& rhs)
  2. You can use memcpy , but the last argument should be the correct size rows*colums*sizeof(double) .您可以使用memcpy ,但最后一个参数应该是正确的大小rows*colums*sizeof(double) sizeof(rhs) is the size of the class object, which is unrelated to the array size. sizeof(rhs)是 class object 的大小,与数组大小无关。 Since you are inside the copy assignment operator and not inside the copy constructor, the memory for mesh is already allocated, so you should remove mesh = new double [rows*columns];由于您在复制赋值运算符中而不是在复制构造函数中,因此已经分配了mesh的 memory,因此您应该删除mesh = new double [rows*columns]; from the copy assignment operator.来自复制赋值运算符。 You also have to do a return *this;您还必须return *this; there to match the return type.在那里匹配返回类型。
  3. Because then you need the const version of the functor: double operator()(size_t i, size_t j) const因为那时您需要仿函数的const版本: double operator()(size_t i, size_t j) const
  4. read about rule of 3 or rule of 5, you should implement the copy constructor if you have a constructor and destructor.阅读规则 3 或规则 5,如果您有构造函数和析构函数,则应该实现复制构造函数。
  5. from @PaulMcKenzie: Use std::vector to not have to do 1, 2, or 4.来自@PaulMcKenzie:使用 std::vector 不必执行 1、2 或 4。

Here is a full example: https://ideone.com/seOSwN这是一个完整的例子: https://ideone.com/seOSwN

I will try and add the missing pieces to your code:我将尝试将缺少的部分添加到您的代码中:

  1. The copy constructor复制构造函数

  2. A working assignment operator.工作分配运算符。

After the code below, I will comment:在下面的代码之后,我将评论:

#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
    }
};

First, note the usage of the member-initialization list to initialize the members of the Mesh2D class.首先,注意使用成员初始化列表来初始化Mesh2D class的成员。 This is a good-habit to do things this way, instead of assigning inside the body of the constructor.以这种方式做事是一个好习惯,而不是在构造函数的主体内分配。


Second, note the assignment operator.其次,注意赋值运算符。 It uses the copy / swap idiom to safely and cleanly deallocate the old memory and make a copy.它使用复制/交换习惯来安全、干净地释放旧的 memory 并进行复制。


Third, the operator() should have a const overload, otherwise you could never use your class in something like this:第三, operator()应该有一个const重载,否则你永远不能像这样使用你的 class :

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

The reason being that m is a const reference, thus you can only call const functions on it.原因是m是一个const引用,因此您只能在其上调用const函数。 Thus, the operator() needs a const version, along with the non-const version.因此, operator()需要一个const版本以及非常量版本。

Also, the reason why the non-const version of operator() needs to also exist is that you may want to do this:此外,非常量版本的operator()也需要存在的原因是您可能想要这样做:

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

If m had only a const version of operator() , the above operation could not be done due to operator() changing the internal state of the object.如果m只有一个const版本的operator() ,则由于operator()更改了 object 的内部 state,因此无法完成上述操作。


Another issue is that you are using memcpy incorrectly.另一个问题是您错误地使用memcpy The memcpy works on the number of bytes, not the number of items in an array. memcpy适用于字节数,而不是数组中的项目数。 Thus you need to multiply by sizeof(double) , since that's the byte count that you are copying.因此,您需要乘以sizeof(double) ,因为这是您要复制的字节数。 A more type-safe solution would be to use std::copy , which automatically uses the correct copying function using the number of items.一个更安全的解决方案是使用std::copy ,它使用项目数自动使用正确的复制 function 。


Last, the test for a bad "Mesh2D" has been removed from the assignment operator.最后,已从赋值运算符中删除了对错误“Mesh2D”的测试。 The reason is that the assignment operator (and copy constructor) job is one thing and one thing only -- make copies.原因是赋值运算符(和复制构造函数)工作是一回事,而且只有一件事——制作副本。

When you start introducing business logic into the copy-assignment functions, you are risking making copies that are not copies, but instead pseudo-copies of the object being passed-in.当您开始将业务逻辑引入到复制分配函数中时,您将冒着制作不是副本的风险,而是制作正在传入的 object 的伪副本。

This leads to some of the nastiest and hardest-to-find bugs in C++, and that is when your copy-assignment functions want to play games and not really make copies.这会导致 C++ 中的一些最讨厌和最难发现的错误,这就是您的复制分配函数想要玩游戏而不是真正复制的时候。 You know when you're doing something wrong if your copy constructor or assignment operator is making too many decisions and executing logic based on the passed-in value.如果您的复制构造函数或赋值运算符根据传入的值做出太多决策并执行逻辑,您就会知道什么时候做错了。


For completion, here is the same version of the class, but using std::vector<double> .为了完成,这里是 class 的相同版本,但使用std::vector<double> Note how much smaller the code is, due to not needing a user-defined assignment operator, copy constructor, or destructor:请注意,由于不需要用户定义的赋值运算符、复制构造函数或析构函数,代码要小得多:

#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