读取数组元素时发生访问冲突

发布于 2024-09-05 15:26:42 字数 3149 浏览 2 评论 0原文

我已经编写了自己的代码来解析 .obj 模型文件 - 本质上只是 ASCII 文本。根据我的测试,该文件被正确解析并存储在类中。我可以在加载函数中很好地读回值(从数据成员)。

当我尝试读回主渲染循环中的值时,就会出现问题。以“int v”开头的行上存在访问冲突错误:

 for(int i = 0; i<data.numFaces; i++){
  for(int j = 0; j<3; j++){ //Assuming triangles for now.

   int v = data.faceList[i].vertex[j]; // Access violation here.
   double vX = data.vertexList[v].x;
   double vY = data.vertexList[v].y;
   double vZ = data.vertexList[v].z;
   glVertex3d(vX, vY, vZ);
  }
 }

我不太确定为什么会发生这种情况,并且我已经检查了我可能想到的所有内容。我对 C++ 不太有经验。尽管我之前用 C++ 编写过一个中型项目,但我的大部分编程经验都是使用 Java、Python 和 PHP 进行的。

我确信问题是与内存分配或用于动态数组的指针相关的基本问题。

以下是 obj 加载类中代码的相关部分:

ObjData ObjLoader::LoadObj(std::string filename){

    //... Initalization ...

 // 1st pass: find number of elements so array sizes can be defined.
 while(!file.eof()){
  //...
 }

 //...close file...

 _data.faceList = new ObjFace[_data.numFaces];
 _data.vertexList = new ObjVert[_data.numVertices];
 _data.uvList = new ObjUV[_data.numUVcoords];
 _data.normalList = new ObjNormal[_data.numNormals];

    //TODO: Make size dynamic according to each face. Just use the first 3 points for now.
 for (int i = 0; i < _data.numFaces; i++){
  _data.faceList[i].vertex = new int[3];
  _data.faceList[i].normal = new int[3];
  _data.faceList[i].uv = new int[3];
 }

 //... file stuff ...

 // 2nd pass: read values into arrays.
 while(!file.eof()){
  //...

  if(type=="v"){
   _data.vertexList[currentVertex].x = atof(param1.c_str());
   _data.vertexList[currentVertex].y = atof(param2.c_str());
   _data.vertexList[currentVertex].z = atof(param3.c_str());
   currentVertex++;
  }else if(type=="vt"){
   _data.uvList[currentUV].u = atof(param1.c_str());
   _data.uvList[currentUV].v = atof(param2.c_str());
   currentUV++;
  }else if(type=="vn"){
   _data.normalList[currentNormal].x = atof(param1.c_str());
   _data.normalList[currentNormal].y = atof(param2.c_str());
   _data.normalList[currentNormal].z = atof(param3.c_str());
   currentNormal++;
  }else if(type=="f"){
  //...Within loop over each vertex in a single face ...

        if(endPos != string::npos){
        // Value before 1st "/" (Vertex index).
        // ...find value in string...
        _data.faceList[currentFace].vertex[i] = atoi(token.c_str()) -1; // File format begins indices from 1.

        // Value between slashes (UV index).
        // ...find value in string...
        _data.faceList[currentFace].uv[i] = atoi(token.c_str()) -1;

        // Value after 2nd "/" (Normal index).
        // ...find value in string...
        _data.faceList[currentFace].normal[i] = atoi(token.c_str()) -1;
   }
//...End of loop over every vertex in a single face...
currentFace++;
}

}

 return _data;

    }

结构 ObjFace、ObjVert、ObjUV 和 ObjNormal 定义为:

    struct ObjVert{
       float x, y, z;
    };

    struct ObjUV{
      float u, v;
    };

    struct ObjNormal{
       float x, y, z;
    };

    // Contains indexes.
       struct ObjFace{
       int* vertex;
       int* uv;
       int* normal;
    };

感谢您的帮助。此外,如果将来有任何关于避免此类错误的好资源,我们将不胜感激。

I've written my own code to parse an .obj model file - essentially just ASCII text. The file gets parsed and stored in the class correctly according to my tests. I can read back the values (from data members) just fine in the loading function.

The problem occurs when I try to read back the values in my main rendering loop. There is an access violation error on the line beginning "int v":

 for(int i = 0; i<data.numFaces; i++){
  for(int j = 0; j<3; j++){ //Assuming triangles for now.

   int v = data.faceList[i].vertex[j]; // Access violation here.
   double vX = data.vertexList[v].x;
   double vY = data.vertexList[v].y;
   double vZ = data.vertexList[v].z;
   glVertex3d(vX, vY, vZ);
  }
 }

I'm not exactly sure why this happens, and I've checked everything I could possibly think of. I'm not very experienced in C++. Most of my programming experience is in Java, Python and PHP although I have previously written a medium sized project in C++.

I'm sure the problem is something basic related to memory allocation or pointers used for the dynamic arrays.

Here are the relevant parts of code in the obj loading class:

ObjData ObjLoader::LoadObj(std::string filename){

    //... Initalization ...

 // 1st pass: find number of elements so array sizes can be defined.
 while(!file.eof()){
  //...
 }

 //...close file...

 _data.faceList = new ObjFace[_data.numFaces];
 _data.vertexList = new ObjVert[_data.numVertices];
 _data.uvList = new ObjUV[_data.numUVcoords];
 _data.normalList = new ObjNormal[_data.numNormals];

    //TODO: Make size dynamic according to each face. Just use the first 3 points for now.
 for (int i = 0; i < _data.numFaces; i++){
  _data.faceList[i].vertex = new int[3];
  _data.faceList[i].normal = new int[3];
  _data.faceList[i].uv = new int[3];
 }

 //... file stuff ...

 // 2nd pass: read values into arrays.
 while(!file.eof()){
  //...

  if(type=="v"){
   _data.vertexList[currentVertex].x = atof(param1.c_str());
   _data.vertexList[currentVertex].y = atof(param2.c_str());
   _data.vertexList[currentVertex].z = atof(param3.c_str());
   currentVertex++;
  }else if(type=="vt"){
   _data.uvList[currentUV].u = atof(param1.c_str());
   _data.uvList[currentUV].v = atof(param2.c_str());
   currentUV++;
  }else if(type=="vn"){
   _data.normalList[currentNormal].x = atof(param1.c_str());
   _data.normalList[currentNormal].y = atof(param2.c_str());
   _data.normalList[currentNormal].z = atof(param3.c_str());
   currentNormal++;
  }else if(type=="f"){
  //...Within loop over each vertex in a single face ...

        if(endPos != string::npos){
        // Value before 1st "/" (Vertex index).
        // ...find value in string...
        _data.faceList[currentFace].vertex[i] = atoi(token.c_str()) -1; // File format begins indices from 1.

        // Value between slashes (UV index).
        // ...find value in string...
        _data.faceList[currentFace].uv[i] = atoi(token.c_str()) -1;

        // Value after 2nd "/" (Normal index).
        // ...find value in string...
        _data.faceList[currentFace].normal[i] = atoi(token.c_str()) -1;
   }
//...End of loop over every vertex in a single face...
currentFace++;
}

}

 return _data;

    }

And the structs ObjFace, ObjVert, ObjUV and ObjNormal are defined as:

    struct ObjVert{
       float x, y, z;
    };

    struct ObjUV{
      float u, v;
    };

    struct ObjNormal{
       float x, y, z;
    };

    // Contains indexes.
       struct ObjFace{
       int* vertex;
       int* uv;
       int* normal;
    };

Thanks for any help. Also, any good sources on avoiding these types of errors in future would be appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

眉目亦如画i 2024-09-12 15:26:42

我输入了一些愚蠢的回复,我意识到这是不对的……但我必须继续思考,然后我想到了另一个想法。

这个对象被分配到哪里?

您的代码不清楚 data_data 是否是同一个对象,但我注意到您的方法似乎返回 _data 作为一个物体。我相信也许您正在某处使用诸如 ObjData data = LoadObj("myfilename"); 之类的赋值?

如果是这种情况,我相信您的问题可能来自于您的 ObjData 类缺少复制构造函数或重载赋值运算符。 (我不是 C++ 专家,所以我不记得这到底属于哪一个。希望其他人可以确认我们是否走在正确的轨道上)。

如果您的指针在复制和赋值期间没有被正确复制(从 LoadObj 返回调用复制构造函数 iirc,然后对 data 进行明显的赋值),那么即使您如果您打算在该位置已有一个 int 数组,那么实际上您可能正在访问未初始化的内存,从而导致访问冲突。

我不是复制构造函数或重载赋值运算符的专家,但解决此问题的快速方法是返回指向 ObjData 的指针,而不是返回对象本身。

I had typed up some silly response which I realized wasn't right...but I had to keep thinking on it, and I came up with another idea.

Where is this object being assigned?

Your code isn't clear if data and _data are the same object or not, but I noticed that your method there seems to return _data as an object. I'm led to believe that perhaps you are using an assignment like ObjData data = LoadObj("myfilename"); somewhere?

If this is the case, I believe your problem may come from a lack of a copy constructor or overloaded assignment operator for your ObjData class. (I'm not a C++ guru, so I don't recall exactly which one this would fall under. Hopefully someone else can confirm if we're on the right track).

If your pointers are not being copied correctly during the copy and assignment (returning from LoadObj calls a copy constructor iirc, and then the obvious assignment to data), then even though you intended to already have an array of int at that location, you may in fact be accessing uninitialized memory, thus causing your Access Violation.

I'm not an expert with either copy constructors or overloaded assignment operators, but a quick way around this would be to return a pointer to an ObjData rather than to return an object itself.

楠木可依 2024-09-12 15:26:42

乍一看,我并没有发现任何明显的错误。但是,如果正如您所说,它在 int v = data.faceList[i].vertex[j]; 处爆炸,那么问题很可能是 ij 或两者都太大或太小。

除了熟悉调试器并消除此错误的明显方法之外,解决此类问题的最佳方法可能是完全避免它们。程序员所做的某些事情比其他事情更容易出错。这个列表很长,但是您在代码中至少执行了其中两个。

1)使用动态分配的数组
2) 使用手工循环

尽量使用 C++ 提供的工具来避免做这些事情。从#1 开始,去掉动态分配的数组。

您有一个结构体:

struct ObjFace{
  int* vertex;
  int* uv;
  int* normal;
};

...带有 3 个int 数组指针。与其这样做,不如使用向量:

struct ObjFace{
  vector<int> vertex;
  vector<int> uv;
  vector<int> normal;
};

...然后您之前必须编写的大量代码现在变得更加简单,并且更不容易出错:

// all this goes away
//_data.faceList = new ObjFace[_data.numFaces];
//_data.vertexList = new ObjVert[_data.numVertices];
//_data.uvList = new ObjUV[_data.numUVcoords];
//_data.normalList = new ObjNormal[_data.numNormals];

...并且:

// now you ask the vector how many elements it really has
for(int i = 0; i<data.faceList.size(); i++){
  for(int j = 0; j<data.faceList.size(); j++){ //Ask the vector instead of assuming triangles

   int v = data.faceList[i].vertex[j]; // Access violation here.
   double vX = data.vertexList[v].x;
   double vY = data.vertexList[v].y;
   double vZ = data.vertexList[v].z;
   glVertex3d(vX, vY, vZ);
  }
 }

现在,看看那个循环。循环是一种非常常见的错误来源。最好的循环是您永远不必编写的循环。所以改用STL的算法吧。向 ObjFace 添加一个函数以在其每个元素上执行 glVertex3d

struct ObjFace{
//... 
  void do_vertex() const 
  {
    typedef vector<int> ints;
    for( ints::iterator it = vertex.begin(); it != vertex.end(); ++it )
      glVertex3d(it->x, it->y, it->z);
  }
};

...然后返回并减少原始循环:
(伪代码,实际语法更复杂)

typedef vector<ObjFace> ObjFaces;
for( ObjFaces::iterator it = data.faceList.begin(); it != data.faceList.end(); ++it )
  it->do_vertex();

...或者,多一点努力:

  for_each( data.faceList.begin(), data.faceList.end(), &ObjFace::do_vertex );

At first glance I didn't see anything blatantly wrong. But if as you say it is exploding at int v = data.faceList[i].vertex[j]; then it seems very likely that the problem is either i or j or both are too big or too small.

Aside from the obvious approach of getting cozy with your debugger and flattening this bug out, the best approach to solving problems like these is probably to avoid them altogether. Certain things programmers do are more prone to errors than others. The list is long, but you do at least two of them, in spades, in your code.

1) You use dynamically-allocated arrays
2) You use hand-crafted loops

Try to avoid doing these things by using the tools that C++ gives you. Start with #1, and get rid of the dynamically-allocated arrays.

You have a struct:

struct ObjFace{
  int* vertex;
  int* uv;
  int* normal;
};

...with 3 pointers-to-arrays-of-int. Instead of doing that, use a vector:

struct ObjFace{
  vector<int> vertex;
  vector<int> uv;
  vector<int> normal;
};

...and then a whole lot of code you had to write before becomes much simpler now, and much less prone to mistakes:

// all this goes away
//_data.faceList = new ObjFace[_data.numFaces];
//_data.vertexList = new ObjVert[_data.numVertices];
//_data.uvList = new ObjUV[_data.numUVcoords];
//_data.normalList = new ObjNormal[_data.numNormals];

...and:

// now you ask the vector how many elements it really has
for(int i = 0; i<data.faceList.size(); i++){
  for(int j = 0; j<data.faceList.size(); j++){ //Ask the vector instead of assuming triangles

   int v = data.faceList[i].vertex[j]; // Access violation here.
   double vX = data.vertexList[v].x;
   double vY = data.vertexList[v].y;
   double vZ = data.vertexList[v].z;
   glVertex3d(vX, vY, vZ);
  }
 }

Now, look at that loop. Loops are a very common source of errors. The best loop is the loop you never have to write. So use the STL's algorithms instead. Add a function to ObjFace to execute glVertex3d on each of it's elements:

struct ObjFace{
//... 
  void do_vertex() const 
  {
    typedef vector<int> ints;
    for( ints::iterator it = vertex.begin(); it != vertex.end(); ++it )
      glVertex3d(it->x, it->y, it->z);
  }
};

...then go back and whittle down that original loop:
(psudocode, actual syntax is more complex)

typedef vector<ObjFace> ObjFaces;
for( ObjFaces::iterator it = data.faceList.begin(); it != data.faceList.end(); ++it )
  it->do_vertex();

...or, with a little more effort:

  for_each( data.faceList.begin(), data.faceList.end(), &ObjFace::do_vertex );
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文