我正在使用C ++和Allegro进行简单的游戏。我遇到有关Access violationvector包含structsunique_ptrsALLEGRO_BITMAPs运行时错误。

这是我的结构声明。

struct Skin {
    std::unique_ptr<ALLEGRO_BITMAP> img;
    Skin();
    Skin(ALLEGRO_BITMAP*);
    Skin& operator=(const Skin& s);
    Skin(const Skin& s);
};


这是另一个文件中的构造函数的定义。

Skin::Skin() {
    img.reset();
}

Skin::Skin(ALLEGRO_BITMAP* bitmap) {
    img.reset(bitmap);
}

Skin::Skin(const Skin& s) {
    img.reset(s.img.get());
}

Skin& Skin::operator=(const Skin& s) {
    img.reset(s.img.get());
    return *this;
}


这是在我的访问冲突发生之前被调用的代码。

generateBase(world, display.get());


哪个调用此函数。

void generateBase(World& world, ALLEGRO_DISPLAY* display) {
    int x = TILESIZE - WIDTH;
    int y = HEIGHT - TILESIZE;
    int groundWidth = 3 * WIDTH - 2 * TILESIZE;
    Point min{ x, y };
    Point max{ x + groundWidth, y + (int)TILESIZE };
    ALLEGRO_BITMAP* black = al_create_bitmap(groundWidth, TILESIZE);
    ALLEGRO_BITMAP* white = al_create_bitmap(groundWidth, TILESIZE);
    al_set_target_bitmap(black);
    al_clear_to_color(al_map_rgb(0, 0, 0));
    al_set_target_bitmap(white);
    al_clear_to_color(al_map_rgb(255, 255, 255));
    al_set_target_bitmap(al_get_backbuffer(display));
    std::cout << "Errors incoming!" << endl;
    createPlayer(world, x, y, 0, 0, 5, vector < AABB > { AABB(min, max) }, vector < Skin > { Skin(black), Skin(white) });
    std::cout << "Did we make it?" << endl;
}


依次调用此函数。

unsigned int createPlayer(World& world, int x, int y, float dx, float dy, float speed, vector<AABB>& mesh, vector<Skin>& imgs) {
    unsigned int entity = newEntityIndex(world);
    world.masks[entity].set(COMPONENT_TYPE);
    world.masks[entity].set(COMPONENT_POINT);
    world.masks[entity].set(COMPONENT_UNITVECTOR);
    world.masks[entity].set(COMPONENT_SPEED);
    world.masks[entity].set(COMPONENT_COLLISIONMESH);
    world.masks[entity].set(COMPONENT_SKINLIST);
    world.types[entity] = TYPE_PLAYER;
    world.points[entity] = Point(x, y);
    world.unitVectors[entity] = UnitVector(dx, dy);
    world.speeds[entity] = Speed(speed);
    world.collisionMeshes[entity].mesh = mesh;
    cout << "Starting vector copy" << endl;
    for (auto skin : imgs) {
        world.skinLists[entity].imgs.push_back(move(skin));
    }
    cout << "Ending vector copy" << endl;
    return entity;
}


这是我的unique_ptr删除器。

namespace std {
    template<>
    class default_delete < ALLEGRO_BITMAP > {
    public:
        void operator()(ALLEGRO_BITMAP* ptr) {
            cout << ptr << endl;
            al_destroy_bitmap(ptr);
        }
    };
}


这是输出。

Errors incoming!
Starting vector copy
00AF9468
00AF9468


通过删除createPlayer修改generateBase中的Skin(white)调用时,输出更改为。

Errors incoming!
Starting vector copy
00799468
Ending vector copy
00799468


输出的变化让我有些困惑,但是我最大的问题是我需要如何更改复制我的vectorstructsunique_ptrs的方式,这样我就不会尝试两次删除同一指针。

提前致谢!

最佳答案

首先要了解的是,您只能有一个std::unique_ptr对象,其中包含指向特定对象的指针。您的Skin(const Skin& s)构造函数违反了此原理,导致unique_ptr的两个副本。如果您的对象包含unique_ptr个成员,则需要执行以下操作之一:


没有复制构造函数或赋值运算符。
在复制构造函数和/或赋值运算符中,分配基础资源的新副本。这将需要调用al_clone_bitmap来复制资源。


其次,当您将资源保存在unique_ptr中时,您想在创建资源的同一位置初始化unique_ptr。例如,代替创建局部变量ALLEGRO_BITMAP* black,请使用以下命令:

std::unique_ptr<ALLEGRO_BITMAP> black(al_create_bitmap(groundWidth, TILESIZE));


由于此代码是直接从unique_ptr的结果创建al_create_bitmap的,因此,您需要删除采用SkinALLEGRO_BITMAP*构造函数,并用以下内容替换:

Skin::Skin(std::unique_ptr<ALLEGRO_BITMAP>&& bitmap)
    : img(bitmap)
{
}


然后可以通过将Skin移到其中来创建unique_ptr

Skin(std::move(black))




综上所述,工作副本构造函数可能如下所示。它不是特别有效,但是很安全。

Skin::Skin(const Skin& s)
    : img(al_clone_bitmap(s.img.get()))
{
}

10-08 20:02