初始化类

时间:2017-04-05 11:43:42

标签: c++

作为练习,我正在翻译我的硕士论文有限差分时域代码,用于模拟从matlab到c ++的波传播,并且我遇到了以下问题。

我想创建一个对应于非物理吸收层的类,称为cpml。图层的大小取决于所需的模拟参数,因此定义吸收层的数组必须是动态的。

#ifndef fdtd_h
#define fdtd_h

#include <cmath>
#include <iostream>
#include <sstream>

using namespace std;

class cpml {

public:

int thickness;
int n_1, n_2, n_3;
double cut_off_freq;
double kappa_x_max, sigma_x_1_max, sigma_x_2_max, alpha_x_max;

double *kappa_x_tau_xy, *sigma_x_tau_xy, *alpha_x_tau_xy;

void set_cpml_parameters_tau_xy();

};

void cpml::set_cpml_parameters_tau_xy(){

double temp1[thickness], temp2[thickness], temp3[thickness];

for(int j = 1; j < thickness; j++){

    temp1[j] = 1 + kappa_x_max * pow((double)(thickness - j - 0.5) / (double)(thickness - 1), n_1);
    temp2[j] = sigma_x_1_max * pow((double)(thickness - j - 0.5) / (double)(thickness - 1), n_1 + n_2);
    temp3[j] = alpha_x_max * pow((double)(j - 0.5) / (double)(thickness - 1), n_3);


}

kappa_x_tau_xy = temp1;
sigma_x_tau_xy = temp2;

for(int i = 1; i < thickness; i++){

    cout << sigma_x_tau_xy[i] << endl;

}

alpha_x_tau_xy = temp3;

}

#endif /* fdtd_h */

当我在main函数中调用函数cpml :: set_cpml_parameters_tau_xy()时,数组sigma_x_tau_xy的第一个值是正确的。但是,其他值不是。

#include "fdtd.h"

using namespace std;

int main() {

cpml cpml;

int cpml_thickness = 10;
cpml.thickness = cpml_thickness;

int n_1 = 3, n_2 = 0, n_3 = 3;
cpml.n_1 = n_1; cpml.n_2 = n_2; cpml.n_3 = n_3;

double cut_off_freq = 1;
cpml.cut_off_freq = cut_off_freq;

double kappa_x_max = 0;
double sigma_x_1_max = 0.8 * (n_1 + 1) / (sqrt(simulation_medium.mu/simulation_medium.rho) * simulation_grid.big_delta_x), sigma_x_2_max = 0.8 * (n_1 + 1) / (sqrt(simulation_medium.mu/simulation_medium.rho) * simulation_grid.big_delta_x);
double alpha_x_max = 2 * PI * cpml.cut_off_freq;

double kappa_y_max = 0;
double sigma_y_1_max = 0.8 * (n_1 + 1) / (sqrt(simulation_medium.mu/simulation_medium.rho) * simulation_grid.big_delta_y), sigma_y_2_max = 0.8 * (n_1 + 1) / (sqrt(simulation_medium.mu/simulation_medium.rho) * simulation_grid.big_delta_y);
double alpha_y_max = 2 * PI * cpml.cut_off_freq;

cpml.kappa_x_max = kappa_x_max; cpml.sigma_x_1_max = sigma_x_1_max; cpml.sigma_x_2_max = sigma_x_2_max; cpml.alpha_x_max = alpha_x_max;
cpml.kappa_y_max = kappa_y_max; cpml.sigma_y_1_max = sigma_y_1_max; cpml.sigma_y_2_max = sigma_y_2_max; cpml.alpha_y_max = alpha_y_max;

cpml.set_cpml_parameters_tau_xy();

for(int j = 1; j < cpml.thickness; j++){

    cout << *(cpml.sigma_x_tau_xy + j) << endl;

}

}

我做错了什么?在主函数中调用时,如何使类cpml的动态数组成员包含正确的值?

2 个答案:

答案 0 :(得分:3)

两个问题:其中较少的是你的程序在技术上不是一个有效的C ++程序,因为C ++没有variable-length arrays(你的数组temp1temp2temp3是。)

更严重的问题是您保存指向局部变量的指针。当函数返回时,局部变量超出范围并且不再存在。指向它们的指针将变为无效,使用这些指针将导致未定义的行为

使用std::vector代替数组和指针可以轻松解决这两个问题。

答案 1 :(得分:0)

如果没有大小的“常量”表达式,则无法在C ++中声明数组(必须在编译时知道边界)。这意味着此代码无效:

double temp1[thickness], temp2[thickness], temp3[thickness];

您应该做的是以下内容:

class cmpl
{
   //...
   std::vector<double> kappa_x_tau_xy, sigma_x_tau_xy, alpha_x_tau_xy;
   // ...
};

void cpml::set_cpml_parameters_tau_xy(){
   alpha_x_tau_xy.resize(thickness);
   kappa_x_tau_xy.resize(thickness);
   sigma_x_tau_xy.resize(thickness);
   //...

std::vector将为您处理所有动态分配。如果您的代码已编译,那是因为您使用了variable length arrays的非标准GCC扩展名。

}在编译时会发出警告,并且应该抱怨更多。

请注意,在数组边界中也存在问题。虽然Matlab是1索引的,但C ++是0索引的,所以你也需要这样做:

-Wall -pedantic -Werror

for(int j = 0; j < thickness; j++){ alpha_x_tau_xy[j] = 1 + kappa_x_max * pow((double)(thickness - j - 0.5) / (double)(thickness - 1), n_1); kappa_x_tau_xy = sigma_x_1_max * pow((double)(thickness - j - 0.5) / (double)(thickness - 1), n_1 + n_2); sigma_x_tau_xy = alpha_x_max * pow((double)(j - 0.5) / (double)(thickness - 1), n_3); } 中有类似的问题:

main

应该成为:

for(int j = 1; j < cpml.thickness; j++){

    cout << *(cpml.sigma_x_tau_xy + j) << endl;

}

附加说明:

  • 您的代码非常非结构化。考虑将所有与for(int j = 0; j < cpml.thickness; j++){ cout << cpml.sigma_x_tau_xy[j] << endl; } 相关的获取和设置放入cmpl类([Encapsulation])(https://en.wikipedia.org/wiki/Encapsulation_(computer_programming))。这将使客户端(在这种情况下)更容易与对象进行交互。

    • 这将包括将您的班级数据隐藏为cmplprotected并公开函数以获取和设置这些变量(请勿忘记private)。
    • 添加构造函数以一次初始化所有字段。就目前而言,你的课程大部分时间都是未初始化的垃圾。如果有人过早地尝试访问某个字段,那么您处于未定义的行为区域。
  • const适用于打印换行符,但将其限制为调试 - 仅限代码。原因是它每次调用时都会刷新缓冲区,如果它打印很多,这会使你的代码整体变慢。使用换行符std::endl代替发布。

  • "\n"的另一个好处是它可以复制并分配给std::vector表现良好的人。否则,编译器将生成一个复制构造函数和复制赋值,使用时将是shallow copy而不是您想要的深层复制

重组课程后,cmpl看起来像这样:

main

哪个可以说更好。 (您可以使用getter从类中获取int main() { int cpml_thickness = 10; int n_1 = 3, n_2 = 0, n_3 = 3; double cut_off_freq = 1; double kappa_x_max = 0; double sigma_x_1_max = 0.8 * (n_1 + 1) / (sqrt(simulation_medium.mu/simulation_medium.rho) * simulation_grid.big_delta_x), sigma_x_2_max = 0.8 * (n_1 + 1) / (sqrt(simulation_medium.mu/simulation_medium.rho) * simulation_grid.big_delta_x); double alpha_x_max = 2 * PI * cut_off_freq; double kappa_y_max = 0; double sigma_y_1_max = 0.8 * (n_1 + 1) / (sqrt(simulation_medium.mu/simulation_medium.rho) * simulation_grid.big_delta_y), sigma_y_2_max = 0.8 * (n_1 + 1) / (sqrt(simulation_medium.mu/simulation_medium.rho) * simulation_grid.big_delta_y); double alpha_y_max = 2 * PI * cut_off_freq; cpml cpml(cpml_thickness, n_1, n_2, n_3, cut_off_freq, kappa_x_max, kappa_y_max, sigma_x_1_max, sigma_x_2max, alpha_x_max, alpha_y_max); cpml.set_cpml_parameters_tau_xy(); cpml.PrintSigmaTauXY(std::cout); } ,然后自己打印)。然后,您可以通过创建表示sigma_tau_xyalpha_x_max等逻辑分组的对象来考虑如何进一步简化事物。这可以是alpha_y_max或完整的结构它自己的吸气剂和二传手。现在他们自己的逻辑被组合在一起,很容易传递/参考/思考。 std::pair的构造函数也变得更简单,您接受一个代表cmplx的参数,而不是两个单独的参数。

Matlab并没有真正鼓励我的(通常是breif)体验中的面向对象方法,但在C ++中它很容易。