作为练习,我正在翻译我的硕士论文有限差分时域代码,用于模拟从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的动态数组成员包含正确的值?
答案 0 :(得分:3)
两个问题:其中较少的是你的程序在技术上不是一个有效的C ++程序,因为C ++没有variable-length arrays(你的数组temp1
,temp2
和temp3
是。)
更严重的问题是您保存指向局部变量的指针。当函数返回时,局部变量超出范围并且不再存在。指向它们的指针将变为无效,使用这些指针将导致未定义的行为。
使用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))。这将使客户端(在这种情况下)更容易与对象进行交互。
cmpl
或protected
并公开函数以获取和设置这些变量(请勿忘记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_xy
和alpha_x_max
等逻辑分组的对象来考虑如何进一步简化事物。这可以是alpha_y_max
或完整的结构它自己的吸气剂和二传手。现在他们自己的逻辑被组合在一起,很容易传递/参考/思考。 std::pair
的构造函数也变得更简单,您接受一个代表cmpl
和x
的参数,而不是两个单独的参数。
Matlab并没有真正鼓励我的(通常是breif)体验中的面向对象方法,但在C ++中它很容易。