@kama1021

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

生ポインタをスマートポインタに置換したら発生した原因不明のエラーを解決したいです。

解決したいこと

VisualStudioでDxLibを使用したゲームを制作しているのですが、
生ポインタを使っていたところをスマートポインタにしてみたら、memoryファイルにて原因不明のエラーが発生し、ビルドできなくなってしまったので、解決方法を知りたいです。

発生している問題・エラー

'=':'_Ux(*const)から'BlletBase *'に変換できません。
'=':'_Ux(*const)から'Enemy *'に変換できません。

該当するソースコード

現状処理部分をmainに直書きしている状態なのですごい冗長になってしまっています。

main.cpp

#include "DxLib.h"
#include <math.h>
#include "Define.h"
#include "GraphicManager.h"
#include <iostream>
#include <memory>

#define DEG2RAD(deg) ((Define::PI / 180) * deg)
#define RAD2DEG(rad) (rad*(180/Define::PI))
#define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0]))

using namespace std;

const int Define::BULLET_MAX = 1024;   //弾の最大数
const int Define::ENEMY_MAX = 64;   //敵の最大数
static char Buf[256];
Image image;
int tmpID = 0;
int tmpScore = 0;

bool autoMoveFlg = false;   //死後の自動移動に使用するフラグ

//プロトタイプ宣言
void eShotManager(int count, int eShotID);

#pragma region クラスの作成とインスタンスの作成

//弾の情報管理クラス
class BulletBase {
public:
    double x;  //弾のx座標
    double y;   //弾のy座標
    double vx;   //弾のxの移動量
    double vy;   //弾のyの移動量
    double angle;   //弾の角度
    double speed;   //弾の速度
    double decision;   //当たり判定

    int image;   //グラフィックハンドル
    bool use;   //使用中かどうか

    double counter;   //発生時からカウントアップしていくカウンタ
};

std::shared_ptr<BulletBase[]> pBullets = std::make_shared<BulletBase[]>(Define::BULLET_MAX);   //プレイヤー用弾を事前に最大数分メモリを確保
std::shared_ptr<BulletBase[]> eBullets = std::make_shared<BulletBase[]>(Define::BULLET_MAX*2);   //エネミー用弾を事前に最大数分メモリを確保

//ボムの情報管理クラス
class Bomb {
public:
    double x;  //x座標
    double y;   //y座標
    double size;   //大きさ
    double image;   //グラフィックハンドル
    bool use;   //使用中かどうか
    int count;   //サインカーブの利用のためのカウンタ
};

Bomb bomb;

//Playerの情報管理クラス
class Player {
public:
    double x;
    double y;
    int image;
    double decision;
};

Player player;   //Playerのインスタンスを作成

//Enemyの情報管理クラス
class Enemy {
public:
    double x;  //敵のx座標
    double y;   //敵のy座標
    double vx;   //敵のxの移動量
    double vy;   //敵のyの移動量
    double angle;   //敵の角度
    double speed;   //敵の速度
    double decision;   //当たり判定

    int image;   //グラフィックハンドル
    bool use;   //使用中かどうか
    int hitPoint;   //体力
};

shared_ptr <Enemy[]> enemys = make_shared<Enemy[]>(Define::ENEMY_MAX);   //敵のインスタンスを生成

#pragma endregion

#pragma region 弾に関する関数
//プレイヤーの弾の情報を設定(使用時に情報をセット)
void pAddBullet(double x, double y, double angle, double speed,int gHundle) {
    for (int i = 0; i < Define::BULLET_MAX; i++)
    {
        //現在の弾が未使用なら
        if (!pBullets[i].use)
        {
            //弾の情報を設定していく
            unique_ptr<BulletBase>  bullet(&pBullets[i]);
            bullet->x = player.x + x;
            bullet->y = player.y + y;
            bullet->angle = angle;
            bullet->speed = speed;

            bullet->image = gHundle;
            bullet->vx = cos(bullet->angle) * speed;
            bullet->vy = sin(bullet->angle) * speed;

            bullet->use = true;
            return;

        }
    }
}
//エネミーの弾の情報を設定(使用時に情報をセット)
void eAddBullet(double x, double y, double angle, double speed,int gHundle,double decision) {
    for (int i = 0; i < Define::BULLET_MAX; i++)
    {
        //現在の弾が未使用なら
        if (!eBullets[i].use)
        {
            //弾の情報を設定していく
            unique_ptr<BulletBase>  bullet (&eBullets[i]);
            bullet->x =x;
            bullet->y =y;
            bullet->angle = angle;
            bullet->speed = speed-bullet->counter;

            bullet->image = gHundle;
            bullet->vx = cos(bullet->angle) * speed;
            bullet->vy = sin(bullet->angle) * speed;
            bullet->decision = decision;

            bullet->use = true;

            bullet->counter = 0;

            return;

        }
    }
}

//自敵ともに弾の描画処理
void DrawBullet(){
    for (int i = 0; i < Define::BULLET_MAX; i++)
    {
        //その弾が使用中なら
        if (pBullets[i].use) {
            unique_ptr<BulletBase>  bullet (&pBullets[i]);   //弾の情報を取得
            DrawRotaGraph(bullet->x, bullet->y, 1.0, 0.0, bullet->image, TRUE, TRUE);
        }
        //その弾が使用中なら
        if (eBullets[i].use) {
            tmpScore++;
            unique_ptr<BulletBase>  bullet (&eBullets[i]);   //弾の情報を取得
            DrawRotaGraph(bullet->x, bullet->y, 1.0, DEG2RAD(180), bullet->image, TRUE, TRUE);
        }
    }
}

//自敵ともに弾の移動処理
void MoveBullet() {
    for (int i = 0; i < Define::BULLET_MAX; i++)
    {
        //自分の弾が使用中なら
        if (pBullets[i].use) {
            unique_ptr<BulletBase>  bullet(&pBullets[i]);   //弾の情報を取得

            //現在の座標に移動量を加算する
            bullet->x += bullet->vx;   
            bullet->y += bullet->vy;

            //画面外にある場合
            if (bullet->y < 0) {
                bullet->use = false;   //そのオブジェクトを不使用にする
            }
        }
        //敵の弾が使用中なら
        if (eBullets[i].use) {
            unique_ptr<BulletBase>  bullet (&eBullets[i]);   //弾の情報を取得

            //現在の座標に移動量を加算する
            bullet->x += bullet->vx;   
            bullet->y += bullet->vy;

            bullet->counter += 0.1;

            //画面外にある場合
            if (bullet->x >Define::PLAY_AREA_RIGIT||bullet->x<Define::PLAY_AREA_LEFT|| bullet->y < Define::PLAY_AREA_UP||bullet->y>Define::PLAY_AREA_DOWN) {
                bullet->use = false;   //そのオブジェクトを不使用にする
            }
        }
    }
}
#pragma endregion

#pragma region ボムに関する関数
//ボムの初期設定
void InitBomb() {
    bomb.x = player.x;
    bomb.y = player.y;
    bomb.size = 0;
    bomb.image = image.getBomb();
    bomb.use=false;
    bomb.count = 0;

}
//ボムの更新処理
void UpdateBomb() {
    bomb.count++;   //サインカーブを利用するためのカウンタ
    if (bomb.count >= 181) bomb.use = false;   //サインカーブの180°地点を超えたら不使用に

    //もしボムが使用中なら
    if (bomb.use == true) {
            bomb.size = sin(DEG2RAD(bomb.count));   //サインカーブに沿ってサイズを変更する
    }

}

//ボムの描画処理
void DrawBomb() {

    DrawRotaGraph(bomb.x, bomb.y,bomb.size,0.0, bomb.image, TRUE);
}
#pragma endregion

#pragma region プレイヤーに関する関数
//Playerの初期設定
void InitPlayer() {
    player.x = Define::PLAYER_START_POS_X;
    player.y = Define::PLAYER_START_POS_Y;
    player.image = image.GetPlayer();
    player.decision = 5.0f;
}

//Playerの描画処理
void DrawPlayer() {
    DrawRotaGraph(player.x, player.y,0.4, 0.0, image.GetPlayer(),TRUE, FALSE);
    if (Buf[KEY_INPUT_LSHIFT] == 1) DrawCircle(player.x, player.y, player.decision,Define::WHITE, TRUE);
}

//Playerの移動処理
void MovePlayer() {

    double moveValue = 0;
    int count = 0;
    int decelerationCheckCount = 0;

    //入力状態の確認
    if (Buf[KEY_INPUT_LEFT] == 1) {
        count++;
    }
    else if (Buf[KEY_INPUT_RIGHT] == 1) {
        count++;
    }
    if (Buf[KEY_INPUT_UP] == 1) {
        count++;
    }
    else if (Buf[KEY_INPUT_DOWN] == 1) {
        count++;
    }
    if (Buf[KEY_INPUT_LSHIFT] == 1) {
        decelerationCheckCount++;
    }

    //移動入力が1つの時(上下左右)
    if (count == 1) {
        moveValue = 10 - (decelerationCheckCount * 7);
    }
    //移動入力が2つの時(斜め)
    if (count != 1) {
        moveValue = (10 - (decelerationCheckCount * 7)) / sqrt(2);
    }

    //動作
    if (Buf[KEY_INPUT_LEFT] == 1) {
        player.x -= moveValue;
    }
    else if (Buf[KEY_INPUT_RIGHT] == 1) {
        player.x += moveValue;

    }
    if (Buf[KEY_INPUT_UP] == 1) {
        player.y -= moveValue;
    }
    else if (Buf[KEY_INPUT_DOWN] == 1) {
        player.y += moveValue;
    }


    if (player.x > Define::PLAY_AREA_RIGIT-10)player.x = Define::PLAY_AREA_RIGIT-10;
    if (player.x < Define::PLAY_AREA_LEFT+10)player.x = Define::PLAY_AREA_LEFT+10;
    if (player.y < Define::PLAY_AREA_UP+10)player.y = Define::PLAY_AREA_UP+10;
    if (player.y > Define::PLAY_AREA_DOWN-10)player.y = Define::PLAY_AREA_DOWN-10;


    //自動移動フラグが真なら
    if (autoMoveFlg == true) {
        //プレイヤーのY座標を-3ずつ移動する
        player.y-=3;
        //プレイヤーのY座標が初期位置以下になったら自動移動フラグを偽にする
        if (player.y <= Define::PLAYER_START_POS_Y) autoMoveFlg = false;
    }
}

#pragma endregion

#pragma region 敵に関する関数
//Enemyの初期設定
void AddEnemy(double x, double y, double angle, double speed, int gHundle) {
    for (int i = 0; i < Define::ENEMY_MAX; i++)
    {
        //現在の敵が未使用なら
        if (!enemys[i].use)
        {
            //敵の情報を設定していく
            unique_ptr<Enemy> enemy (&enemys[i]);
            enemy->x = x;
            enemy->y = y;
            enemy->angle = angle;
            enemy->speed = speed;

            enemy->image = gHundle;
            enemy->vx = cos(enemy->angle) * speed;
            enemy->vy = sin(enemy->angle) * speed;

            enemy->use = true;
            return;
        }
    }
}


//敵の描画処理
void DrawEnemy() {
    for (int i = 0; i < Define::ENEMY_MAX; i++)
    {
        //その敵が使用中なら
        if (enemys[i].use) {
            unique_ptr< Enemy> enemy (&enemys[i]);   //敵の情報を取得
            DrawRotaGraph(enemy->x, enemy->y, 1.0, 0.0, enemy->image, TRUE, TRUE);
        }
    }
}

//敵の更新処理
void UpdateEnemy(int count) {
    eShotManager(count, tmpID);
    }

//}
//敵の移動処理
void MoveEnemy(int count) {
    for (int i = 0; i < Define::ENEMY_MAX; i++)
    {   int tmpCount=0;
        //自分の敵が使用中なら
        if (enemys[i].use) {
            unique_ptr<Enemy> enemy (&enemys[i]);   //敵の情報を取得

            //移動量を加算
                enemy->x += enemy->vx;
                enemy->y += enemy->vy;
            //画面外にある場合
            if (enemy->x > Define::PLAY_AREA_RIGIT || enemy->x < Define::PLAY_AREA_LEFT || enemy->y < Define::PLAY_AREA_UP || enemy->y>Define::PLAY_AREA_DOWN) {
                enemy->use = false;   //そのオブジェクトを不使用にする
            }
        }

    }
}
#pragma endregion


//Playerの当たり判定
void Collision() {
    //現在画面上に描画されている弾の座標を取得する
    for (int i = 0; i < Define::BULLET_MAX; i++)
    {
        //その弾が使用中なら
        if (eBullets[i].use) {
            unique_ptr<BulletBase>  bullet (&eBullets[i]);   //弾の情報を取得

            //各値を取得する
            bullet->x;
            bullet->y;

            player.x;
            player.y;

            //必要な計算をする
            double x = bullet->x - player.x;   //弾とプレイヤーのX座標の距離
            double y = bullet->y - player.y;   //弾とプレイヤーのY座標の距離
            double r = bullet->decision+player.decision;   //弾とプレイヤーの当たり判定の合算

            //円と円の当たり判定
            //(弾の座標とプレイヤーの座標の距離)が(弾の半径+プレイヤーの当たり判定)以下である

            if (sqrt(pow(x,2) + pow(y,2)) < sqrt(r)) {
                //敵の弾をすべて消す
                for (int i = 0; i < Define::BULLET_MAX; i++){
                        eBullets[i].use = false;
                }
                //座標をリセット
                player.x = Define::PLAYER_START_POS_X;
                player.y = Define::PLAYER_START_POS_Y+200;
                tmpScore = 0;

                autoMoveFlg = true;   //自動移動フラグを真に
            }
        }
    }
}

//プレイヤーのショットの管理
void ShotManager(int count, int* playerLevel) {
    int nomalBullet = image.GetBullet();
    int addBullet = image.GetAddBullet();
    //一時的なレベルの管理
    if (Buf[KEY_INPUT_0] == 1) {
        *playerLevel = 0;
    }
    if (Buf[KEY_INPUT_1] == 1) {
        *playerLevel = 1;
    }
    if (Buf[KEY_INPUT_2] == 1) {
        *playerLevel = 2;
    }
    if (Buf[KEY_INPUT_3] == 1) {
        *playerLevel = 3;
    }
    if (Buf[KEY_INPUT_4] == 1) {
        *playerLevel = 4;
    }
    //ショットキーが押されたら
    if (Buf[KEY_INPUT_Z] == 1) {
        //3フレームに1回弾を出す
        if (count % 3 == 0) {
            if (Buf[KEY_INPUT_LSHIFT] == 0) {
                pAddBullet(10, 0, DEG2RAD(270), Define::BULLET_SPEED, nomalBullet);   //標準装備1
                pAddBullet(-10, 0, DEG2RAD(270), Define::BULLET_SPEED, nomalBullet);   //標準装備2
                if (*playerLevel < 1) return;
                pAddBullet(30, -30, DEG2RAD(285), Define::BULLET_SPEED, addBullet);   //レベル1の追加弾
                if (*playerLevel < 2) return;
                pAddBullet(-30, -30, DEG2RAD(255), Define::BULLET_SPEED, addBullet);   //レベル2の追加弾
                if (*playerLevel < 3) return;
                pAddBullet(40, 0, DEG2RAD(300), Define::BULLET_SPEED, addBullet);   //レベル3の追加弾
                if (*playerLevel < 4) return;
                pAddBullet(-40, 0, DEG2RAD(240), Define::BULLET_SPEED, addBullet);   //レベル4の追加弾
            }
            else if (Buf[KEY_INPUT_LSHIFT] == 1) {

                pAddBullet(10, 0, DEG2RAD(270), Define::BULLET_SPEED, nomalBullet);   //標準装備1
                pAddBullet(-10, 0, DEG2RAD(270), Define::BULLET_SPEED, nomalBullet);   //標準装備2
                if (*playerLevel < 1) return;
                pAddBullet(30, -30, DEG2RAD(270), Define::BULLET_SPEED, addBullet);   //レベル1の追加弾
                if (*playerLevel < 2) return;
                pAddBullet(-30, -30, DEG2RAD(270), Define::BULLET_SPEED, addBullet);   //レベル2の追加弾
                if (*playerLevel < 3) return;
                pAddBullet(40, 0, DEG2RAD(270), Define::BULLET_SPEED, addBullet);   //レベル3の追加弾
                if (*playerLevel < 4) return;
                pAddBullet(-40, 0, DEG2RAD(270), Define::BULLET_SPEED, addBullet);   //レベル4の追加弾

            }
        }
    }

    //ボムキーが押されたら
    if (Buf[KEY_INPUT_X] == 1 && bomb.use == false) {
        InitBomb();
        bomb.use = true;
        for (int i = 0; i < Define::BULLET_MAX; i++)
        {
                eBullets[i].use = false;
        }
    }

}

//敵の弾幕の管理
void eShotManager(int count,int eShotID) {
    int a = 0;
    int b = 0;
    int ang = 0;
    a= 400 - (int)player.x;
    b = 200 - (int)player.y;
    ang = RAD2DEG(atan2(b, a))-180;
    for (int i = 0; i < Define::ENEMY_MAX; i++) {
        //自分の敵が使用中なら
        if (enemys[i].use) {
            unique_ptr<Enemy> enemy(&enemys[i]);   //敵の情報を取得
            switch (eShotID)
            {
            case 0: {
                //全方位高密度弾幕
                if (count % 3 == 0) {
                    int speed = 3;
                    int size = 5;
                    for (int i = 0; i < 10; i++) {
                        eAddBullet(enemy->x, enemy->y, DEG2RAD(i*36 + count), speed, image.geteNomalBullets()[i], size);

                    }

                }
                break;
            }
            case 1: {
                //自機向き波状弾
                for (int i = -40; i < 40; i+=20)
                {
                    int size = 5;
                    int timing = 10;
                    if (count % timing == 0) {
                        eAddBullet(enemy->y, enemy->y, DEG2RAD((ang + i + 0)), 7, image.geteNomalBullets()[0], size);
                    }
                    else if ((count + 2) % timing == 0) {
                        eAddBullet(enemy->x, enemy->y, DEG2RAD((ang + i + 5)), 6.5, image.geteNomalBullets()[1], size);
                    }
                    else if ((count + 4) % timing == 0) {
                        eAddBullet(enemy->x, enemy->y, DEG2RAD((ang + i + 10)), 6, image.geteNomalBullets()[2], size);
                    }
                    else if ((count + 6) % timing == 0) {
                        eAddBullet(enemy->x, enemy->y, DEG2RAD((ang + i + 15)), 5.5, image.geteNomalBullets()[3], size);
                    }
                    else if ((count + 8) % timing == 0) {
                        eAddBullet(enemy->x, enemy->y, DEG2RAD((ang + i + 20)), 5, image.geteNomalBullets()[4], size);
                    }
                };
                break; }
                  //敵中心のぐるぐる弾
            case 2: {
                if (count % 1 == 0) {
                    int speed = 5;
                    int size = 3;
                    int hoge = 180;
                    eAddBullet(enemy->x + (GetRand(2) - 1), enemy->y + (GetRand(2) - 1), DEG2RAD((count + hoge)) * 5, speed + 3, image.geteNomalBullets()[0], size);
                    eAddBullet(enemy->x + (GetRand(2) - 1), enemy->y + (GetRand(2) - 1), -DEG2RAD(count) * 5, speed + 3, image.geteNomalBullets()[0], size * 2);
                }
                break; }
            default:
                break;
            }
        }
    }
}



void tmpUpdate() {
    //エンターが押されたら
    if (Buf[KEY_INPUT_RETURN] == 1) {

        AddEnemy(Define::PLAYER_START_POS_X, (Define::PLAY_AREA_Y / 5) * 2 + Define::PLAY_AREA_UP, DEG2RAD(GetRand(360)), 1, image.GetEnemy01());   //敵を追加
        tmpID = GetRand(2);   //敵が使う弾幕をランダムで決定
        WaitTimer(180);   //余分に敵を複製しないように一時的な処理(後ほど然るべき処理に変更)
    }
}
// プログラムは WinMain から始まります
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    SetGraphMode(Define::WINDOW_X,Define::WINDOW_Y, 32);   //画面モードの設定
    ChangeWindowMode(TRUE);   //ウィンドウモード
    if (DxLib_Init() == -1)   // DXライブラリ初期化処理
    {
        return -1;   // エラーが起きたら直ちに終了
    }

    //初期設定(ここではオブジェクトの動きを伴うものは呼び出さない)
    int playerLevel = 0;
    image.Init();
    InitPlayer();


    int count = 0;
    while (ProcessMessage() == 0) {
        ClearDrawScreen();   //画面をクリアする


        GetHitKeyStateAll(Buf);   //すべてのキーの入力状態を取得(ここで一度しか呼ばない)(後ほど然るべき関数にする)
        count++;   //共通のカウンター(これも然るべき関数にする)
        ShotManager(count, &playerLevel);

        UpdateBomb();
        tmpUpdate();
        UpdateEnemy(count);

        MoveBullet();
        MovePlayer();
        MoveEnemy(count);

        DrawBullet();
        DrawPlayer();
        DrawBomb();
        DrawEnemy();
        DrawGraph(0, 0, image.GetBackGround(), TRUE);
        DrawFormatString((Define::WINDOW_X / 3) * 2,  (Define::WINDOW_Y / 10) * 1,Define::WHITE, "score  %d",tmpScore);

        Collision();
        //60fps 1秒間に画面を60回更新する
        //1秒1000ms/60=16.666msに画面を1回更新する
        WaitTimer(16);   //16ms待つ
        clsDx();
        ScreenFlip();
    }

    WaitKey();   // キー入力待ち

    DxLib_End();   // DXライブラリ使用の終了処理

    return 0;   // ソフトの終了 
}

エラー発生部

memory
  template <class _Ux>
    void _Set_ptr_rep_and_enable_shared(_Ux* const _Px, _Ref_count_base* const _Rx) noexcept { // take ownership of _Px
        this->_Ptr = _Px;
        this->_Rep = _Rx;
        if constexpr (conjunction_v<negation<is_array<_Ty>>, negation<is_volatile<_Ux>>, _Can_enable_shared<_Ux>>) {
            if (_Px && _Px->_Wptr.expired()) {
                _Px->_Wptr = shared_ptr<remove_cv_t<_Ux>>(*this, const_cast<remove_cv_t<_Ux>*>(_Px));
            }
        }
    }

memoryファイルの1784行目にてIntelliSenseのサンプルテンプレート引数を指定してください。
と表示されます。

自分で試したこと

どこでエラーが発生したのか分かってない状態なので、何も試せてないです。

0 likes

1Answer

std::shared_ptr<BulletBase[]> pBullets = std::make_shared<BulletBase[]>(Define::BULLET_MAX);   //プレイヤー用弾を事前に最大数分メモリを確保
std::shared_ptr<BulletBase[]> eBullets = std::make_shared<BulletBase[]>(Define::BULLET_MAX*2);   //エネミー用弾を事前に最大数分メモリを確保

https://cpprefjp.github.io/reference/memory/make_shared.html
make_sharedで配列を作れるようになるのは C++20 からです

std::shared_ptr<BulletBase[]> pBullets(new BulletBase[Define::BULLET_MAX]);

コンパイラが使用する C++言語のバージョンを変更するか、上記のように書き換えましょう


            //敵の情報を設定していく
            unique_ptr<Enemy> enemy (&enemys[i]);

unique_ptrに他のインスタンスが所有権を持っているポインタを突っ込むのはやめましょう
2重解放が発生してメモリを破壊するので大変危険です
ソース中のunique_ptrの使い方は全部間違っています

毎回

 enemy[i]->x = x;
 enemy[i]->y = y;

と書きたくないだけなら 参照を使えば十分なはずです

auto enemy = &enemys[i];
enemy->x = x;
enemy->y = y;

or

auto& enemy = enemys[i];
enemy.x = x;
enemy.y = y;

こう書きましょう

1Like

Comments

  1. @kama1021

    Questioner

    具体的なコードまで送って頂きありがとうございます!!
    C++のバージョンを最新にしたらバグは消えました!
    ポインタやメモリについては勉強中なので、教えていただいたことをこれから生かしていきます!

Your answer might help someone💌