首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >二维网格类在C++中的实现

二维网格类在C++中的实现
EN

Stack Overflow用户
提问于 2020-07-03 07:22:17
回答 2查看 417关注 0票数 2

我想要实现一个2D网格类,这是内存效率,因为它将用于蒙特卡罗模拟。然而,在这个阶段,这实际上与2D数组类相同。不用说,我是C++的新手。我写了以下代码。

代码语言:javascript
复制
#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
代码语言:javascript
复制
//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);

}

我的问题是作为评论写的,但我在这里也列出了它们:

复制构造函数内部的inline operator=(const Mesh2D& rhs)

  1. ,这一行Mesh2D& operator=(const Mesh2D& rhs)和此行Mesh2D& operator=(const Mesh2D& rhs)之间的区别是什么?

  1. ,在复制构造函数中,我想避免使用for循环,而是使用memcpy。但是,输出不是预期的,我做错了什么?

主函数内部的void PrintMesh2D(const Mesh2D &mesh)

  • :为什么不编译?

  1. 最后,实现完成了吗?我的意思是,有什么重要的特性/功能缺失了吗?

欢迎你给我任何建议。由于我是C++新手,我有一种感觉,我正在编写错误的buggy代码。

编辑:

我以复制构造函数的形式编写了以下内容。

代码语言:javascript
复制
/* 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;
    } 

看上去对吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-07-03 08:23:49

我将尝试将缺失的部分添加到代码中:

  1. 复制构造函数

  1. 工作分配操作符.

在下面的代码之后,我将评论:

代码语言:javascript
复制
#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类的成员。这样做是一个好习惯,而不是在构造函数的主体内分配。

第二,注意赋值操作符。它使用copy / swap idiom安全、干净地释放旧内存并复制。

第三,operator()应该有一个const重载,否则您就永远不能在这样的事情中使用类:

代码语言:javascript
复制
void foo(const Mesh2D& m)
{
   std::cout << m(0,0);
}

原因是mconst引用,因此只能在其上调用const函数。因此,operator()需要一个const版本,以及非const版本。

此外,operator()的非const版本也需要存在的原因是您可能希望这样做:

代码语言:javascript
复制
void foo2(Mesh2D& m)
{
   m(0,0) = 23;
}

如果m只有const版本的operator(),则由于operator()更改对象的内部状态,无法执行上述操作。

另一个问题是您使用memcpy不正确。memcpy工作在字节数上,而不是数组中的项目数。因此,您需要被sizeof(double)乘以,因为这是要复制的字节计数。更安全的解决方案是使用std::copy,它使用项目数自动使用正确的复制函数。

最后,错误的"Mesh2D“测试已经从赋值操作符中删除。原因是赋值操作符(和复制构造函数)作业是一回事,只有一件事--复制副本。

当您开始在副本分配函数中引入业务逻辑时,您就有可能创建不是副本的副本,而是正在传递的对象的伪副本。

这导致了C++中一些最讨厌和最难找到的bug,也就是当您的复制分配函数想玩游戏而不是真正复制的时候。如果您的复制构造函数或赋值操作符基于传递的值做出太多的决策和执行逻辑,那么您知道什么时候做错了什么。

为了完成,这里是类的相同版本,但使用std::vector<double>。请注意,由于不需要用户定义的赋值操作符、复制构造函数或析构函数,代码有多小:

代码语言:javascript
复制
#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]; 
    }
};
票数 2
EN

Stack Overflow用户

发布于 2020-07-03 07:33:11

  1. inline operator=(const Mesh2D& rhs)是语法错误,它错过了返回类型。另外,Mesh2D(const Mesh2D& rhs).
  2. You可以使用Mesh2D& operator=(const Mesh2D& rhs),但最后一个参数应该是正确的rows*colums*sizeof(double)大小,因此Mesh2D& operator=(const Mesh2D& rhs)是复制赋值操作符,而不是复制构造函数。sizeof(rhs)是类对象的大小,它与数组大小无关。由于您是在复制赋值操作符中而不是在复制构造函数中,所以mesh的内存已经被分配了,所以您应该从复制赋值操作符中删除mesh = new double [rows*columns];。您还必须在那里做一个与返回type.
  3. Because相匹配的return *this;,然后您需要函子的const版本:double operator()(size_t i, size_t j) const
  4. read关于规则3或规则5,如果您有一个构造函数,并且destructor.
  5. from @PaulMcKenzie :使用std::vector不需要做1、2或4,则应该实现复制构造函数。

下面是一个完整的示例:https://ideone.com/seOSwN

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62710399

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档