【发布时间】:2021-01-16 17:06:18
【问题描述】:
我正在尝试从 Lubos Brieda(等离子模拟示例)重新创建等离子模拟。为此,我需要实现一个 3D 场,其中填充了包含电场数据的物理矢量。 (我不想使用模板,我指的是数学/物理意义上的向量。)
本书展示了如何创建 Field 和 vec3 类,以创建具有三个组件的特定类型和数组(向量)的字段。
我的目标是找到实现矢量场的最简单方法,如上所述。由于书中提到 Field3(= Field_<vec3<double>>) 类型已经实现(但还没有实现),我认为有一个简单的选项可以做到这一点,而不必创建一个新类。我试过using Field3 = Field_<vec3<double>>,但总是导致以下错误:
Exception thrown: read access violation. **a** was nullptr.
您可以在下面看到导致错误的代码,包括上面提到的类。 (我想我排除了所有不必要的内容。我留下了一些带有代码行的 cmets,您可以使用这些代码行来查看其余代码是否正常工作,只有 Field3 类型会引发错误。)
#include<iostream>
#include"World.h"
#include"Field_.h"
#include"vec3.h"
int main() {
World world(21, 21, 21);
return 0;
}
template <typename T>
struct vec3 {
// assign data
vec3(const T u, const T v, const T w) : d{ u,v,w } {}
vec3(const T a[3]) : d{ a[0],a[1],a[2] } {}
vec3() : d{ 0,0,0 } {}
//protected:
T d[3];
};
using double3 = vec3<double>; // three component vector with doubles
using int3 = vec3<int>;
#pragma once
#include"vec3.h"
template<typename T>
class Field_ { // underscore for undefined type
public:
// constructor
Field_(int ni, int nj, int nk) : ni{ ni }, nj{ nj }, nk{ nk }{
data = new T * *[ni]; // ni pointers to pointers of type T
for (int i = 0; i < ni; i++) {
data[i] = new T * [nj]; // allocte nj pointers to T
for (int j = 0; j < nj; j++)
data[i][j] = new T[nk]; // allocate nk objects of type T
}
operator=(0); // call the overloaded operator= function (initialize with 0)
}
// destructor, frees memory in reverse order
~Field_() {
if (data == nullptr) return; // return if unallocated
for (int i = 0; i < ni; i++) { // release memory in reverse order
for (int j = 0; j < nj; j++)
delete data[i][j];
delete data[i];
}
delete[] data;
data = nullptr; // mark as free
}
// overload the assignment operator
Field_<T>& operator= (const T s) {
std::cout << "Field_ operator=" << std::endl;
for (int i = 0; i < ni; i++)
for (int j = 0; j < nj; j++)
for (int k = 0; k < nk; k++)
data[i][j][k] = s;
return *this; // return reference to self
}
const int ni, nj, nk; // number of nodes
protected:
T*** data; // pointer of type T
};
using Field = Field_<double>; // field of doubles (scalar field)
using Field3 = Field_<double3>; // field of double3s (vector field)
#pragma once
#include"vec3.h"
#include"Field_.h"
class World {
public:
World(int ni, int nj, int nk); //constructor
const int ni, nj, nk;
//Field phi; //electric potential (scalar field)
Field3 ef; //electric field (vector field)
};
//World::World(int ni, int nj, int nk): ni{ ni }, nj{ nj }, nk{ nk }, phi(ni, nj, nk){}
//World::World(int ni, int nj, int nk) : ni{ ni }, nj{ nj }, nk{ nk }, phi(ni, nj, nk), ef(ni, nj, nk) {}
World::World(int ni, int nj, int nk) :
ni{ ni }, nj{ nj }, nk{ nk }, ef(ni, nj, nk) {}
我希望你能帮我弄清楚该怎么做,如果我能在此期间提供任何帮助,请告诉我。
【问题讨论】:
-
由于您似乎遇到了一个高度可重复的问题,是时候部署您的开发环境附带的调试器了。当程序崩溃时,调试器通常会停止,并允许您检查崩溃站点以寻找线索。然后,您使用收集到的线索来查看接下来应该检查的内容。使用断点将程序推进到感兴趣的位置,然后逐行执行程序以查找意外情况,程序通常存储错误的值或采取错误的路径。意外几乎总是一个错误。
-
仔细检查
operator=(0)。这几乎可以肯定是错误。operator=期望用T调用,它会尽一切努力将该 0 转换为T,包括调用vec3构造函数并将 0 转换为空指针。 -
一旦你将
data成员的类型T***替换为std::vector<T>,然后计算3D该连续数组的子集索引。专业的密集张量/数组/场实现几乎总是连续的一维数组,而不是嵌套数组。 -
旁注:
delete data[i][j];应该是delete[] data[i][j];和delete data[i];应该是delete[] data[i];因为你正在处理数组。 -
感谢到目前为止的 cmets!我使用调试器工作,我相信问题出在
operator=和vec3的构造函数上。您认为可以对标量值以及我的三分量向量使用相同的Field_类吗?还是有问题,因为一个需要比另一个更多的指向指针?
标签: c++ simulation