0

私は次のような構造体の配列へのポインタを持っています:

class Terrian  {
     ...
    private:
        Vector *terrian_vertices;
     ...
}

そして、ポインタのデータは「construct_vertices」関数で生成されます

Terrian::Terrian(int width, int height)  {
    this->width = width;
    this->height = height;

    std::cout << "Width: " << width << "  Height: " << height << "\n";

    std::cout << "Vertices\n";
    construct_vertices();
    std::cout << "Element\n";
    construct_elements();
    std::cout << "Buffers\n";
    construct_buffers();
}

void Terrian::construct_vertices()  {
    terrian_vertices = new Vector[width * height];

    std::cout << "Generating data\n";

    for (int x = 0; x < width; x++)  {
        for (int y = 0; y < height; y++)  {
            int index = x + y * width;

            Vector *pos = new Vector((GLfloat)x, 0.0f, (GLfloat)-y);
            memcpy(pos, terrian_vertices, sizeof(Vector) * index);

            std::cout << terrian_vertices[index].x;

            Color *color = new Color(0, 255, 0);
            memcpy(color, terrian_colors, sizeof(Color) * index);
        }
    }
}

これがプログラムの出力です(メイン関数で行うのはオブジェクトをインスタンス化することだけです)

Width: 32  Height: 32
Vertices
Generating data
5.2349e-039
Process returned -1073741819 (0xC0000005)   execution time : 10.073 s
Press any key to continue.

最初のポインタが配列にコピーされるとプログラムがクラッシュし、「x」の出力は0になるはずです。これは不可解です。何がこれを引き起こしているのか誰かが知っていますか?もしそうなら、memcpyを使用せずに構造体を動的に割り当てるより良い方法はありますか?

4

2 に答える 2

5

何がこれを引き起こしているのか誰かが知っていますか?

の使用memcpyは正しくありません。どんな参考資料でもそれを教えてくれます。

最初のパラメーターは、配列indexへの要素となる宛先へのポインターです。terrian_verticesterrian_vertices + index

2番目のパラメーターは、ソースへのポインターですpos

(興味がある場合は、宛先がソースの前に来る理由は、代入演算子と並列であるためですdestination = source:)

3番目のパラメーターは、コピーするデータの量です。これは、あなたの場合は次のようになります。コピーする必要があるのは1つsizeof(Vector)だけであり、ではありません。 Vectorindex

コードのように誤用memcpyすると、未定義の動作が発生しやすくなり、幸いにもエラーとして現れます。

もしそうなら、memcpyを使用せずに構造体を動的に割り当てるより良い方法はありますか?

はい。自分でメモリを管理しないでくださいstd::vector。通常のコピーセマンティクスを使用してください。

class Terrian  {
// ...
private:
    std::vector<Vector> terrain_vertices;
    // Hmm, this may need some touch up on naming,
    // or it may get confusing with two "vector" thingies around
};

// ...

void Terrian::construct_vertices()  {
    terrain_vertices.reserve(width * height);
     // reserve is actually optional,
     // but I put it here to parallel the original code
     // and because it may avoid unneeded allocations

    std::cout << "Generating data\n";

    for (int x = 0; x < width; x++)  {
        for (int y = 0; y < height; y++)  {
            terrain_vertices.emplace_back((GLfloat)x, 0.0f, (GLfloat)-y);
            // or this if your compiler doesn't support C++11:
            // terrain_vertices.push_back(Vector((GLfloat)x, 0.0f, (GLfloat)-y));

            std::cout << terrian_vertices[index].x;

            // same thing for colors
            terrain_colors.emplace_back(0, 255, 0);
        }
    }

今、newどこにも見えないことに注目してください。これにより、元のコードの別の問題が解決されます。ループごとの反復の1つVectorのインスタンスと1つのインスタンスがリークしていました。Color

于 2012-07-16T01:00:47.187 に答える
0
Vector *pos = new Vector((GLfloat)x, 0.0f, (GLfloat)-y);
memcpy(pos, terrian_vertices, sizeof(Vector) * index);

あなたはそれをすることはできません。 newに十分なメモリを割り当て、そこVectorposポイントします。ただし、次にsizeof(Vector) * indexバイトをその場所にコピーします。初めては0であるため、これint index = x + y * width;は0バイトになります。次回は2*幅, which is likely greater than1 , so you end up copying past*pos`で人のいない土地になります。

memcpyちなみに、複雑なタイプのコピーには使用しないでください。必要なのは大丈夫でビットコピー用のビットだけかもしれませんが、一部のタイプ(つまり、RAIIスタイルのコンテナーなどの内部セマンティクスのためにビットコピーできないタイプ)で使用すると、これはうまくいかない可能性があります。

于 2012-07-16T00:46:59.557 に答える