变量如果不是从代码中更改,为什么会突然更改其值?

huangapple go评论65阅读模式
英文:

Why can the variable change its value suddenly if I don't change it from the code?

问题

在我的代码中,当用户按下ENTER键后,我创建了3个子弹。它们之间有一个名为NEXT_SHOT_IN_CHAIN_DELAY的延迟。当按下ENTER键时,我创建了三个Shot类的对象,并将它们添加到std::vector <Shot*> shots中。Shot类将内部状态从以下值更改为2:

WAIT_FOR_SHOT_START -> BULLET_LEFT_WEAPON -> BULLET_IN_ATTACK_ZONE

根据程序启动时的当前时间,当我创建class shot的实例时,子弹的编号和离开武器的开始时间(变量startShotTime)具有正常值。

控制台输出:

    DEBUG: Bullet by creation: 0; Start shot time: 3833; End shot time: 4583 and statement: 0; Actual time: 4583
    DEBUG: Bullet by creation: 1; Start shot time: 4163; End shot time: 4913 and statement: 0; Actual time: 4913
    DEBUG: Bullet by creation: 2; Start shot time: 4493; End shot time: 5243 and statement: 0; Actual time: 5243

在每一帧中,我更新所有的子弹。在更新函数中,我的日志记录器告诉我,子弹编号和startShotTime已经具有新的(奇怪的)值。

控制台输出:

    DEBUG: Bullet 258744461 Start shot time: 575665160
    DEBUG: Bullet 575663496 Start shot time: 3744914323
    DEBUG: Bullet 575663688 Start shot time: 575663624

什么可以改变我的私有变量的值?

Bullet类只是屏幕上子弹的图形演示,它不影响Shot类。

如果这很重要:我在Windows 10上使用VisualStudio和SDL2库。

以下是我的代码,BulletController.h的部分:

#pragma once
#include <vector>
#include "Timer.h"
#include "Logger.h"
#include <vector>
#include "FightersController.h"
#include "Bullet.h"
#include "Random.h"
#include "Shot.h"
#include "EventsListener.h"

class BulletController {
public:
    BulletController(FightersController* fightersController, Bullet *bullets, int bulletsNumber);
    ~BulletController();
    void update(long deltaTime);

private:
    int bulletsNumber;
    const int BULLETS_PART_TO_BE_RENDERED_IN_PERCENTS = 60;
    Bullet* bullets;
    FightersController* fightersController = nullptr;
    const int NOTHING_TO_DELETE = -1;
    std::vector <Shot*> shots;
    int shotNumberToBeDeleted = NOTHING_TO_DELETE;
    void makeExplosion(int numberOfBullet);
    void updateShooting();
    void startToShotIfPossible();
    void updateActualBullets();
    void setVisibilityForBullets();
    const int bulletsInLine = 3;
    const int NEXT_SHOT_IN_CHAIN_DELAY = 330;
    bool shotAlreadyPressed;
    // Mutable
    Random* mutRandomizer;
};

BulletController.cpp的部分:

#include "BulletController.h"

BulletController::BulletController(FightersController* fightersController, Bullet *bullets, int bulletsNumber) {
    this->bullets = bullets;
    this->bulletsNumber = bulletsNumber;
    this->fightersController = fightersController;
    mutRandomizer = new Random();
}

BulletController::~BulletController() {
    delete mutRandomizer;
    delete bullets;
}

void BulletController::update(long deltaTime) {
    updateActualBullets();
    updateShooting();
}

void BulletController::updateShooting() {
    std::vector <Command>* commands = EventsListener::getInstance()->getCommands();
    bool shotCommandFounded = false;
    if (commands->size() > 0) {
        for (auto i = (commands->begin()); i != commands->end(); ++i) {
            Command command = (Command)*i; //This copies the command
            if (command.getType() == command_constants::SHOT) {
                Logger::debug("Player pressed shot");
                if (!shotAlreadyPressed) {
                    shotAlreadyPressed = true;
                    startToShotIfPossible();
                }
                shotCommandFounded = true;
            }
        }
    }
    if (shotAlreadyPressed) {
        if (!shotCommandFounded) {
            shotAlreadyPressed = false;
        }
    }
}

void BulletController::updateActualBullets() {
    if (shots.size() > 0) {
        int toBeDeleted = -1;
        int itterator = 0;
        for (auto i : shots) {
            i->update();
        }
        for (auto i : shots) {
            if (i->isInHitZone()) {
                makeExplosion(itterator);
                toBeDeleted = itterator;
            }
            itterator++;
        }
        if (toBeDeleted >= 0) {
            shots.erase(shots.begin() + toBeDeleted);
        }
    }
}

void BulletController::startToShotIfPossible() {
    Shot firstShot(0);
    shots.push_back(&firstShot);
    Shot secondShot(NEXT_SHOT_IN_CHAIN_DELAY);
    shots.push_back(&secondShot);
    Shot thirdShot(NEXT_SHOT_IN_CHAIN_DELAY * 2);
    shots.push_back(&thirdShot);
    setVisibilityForBullets();
    Logger::debug("Shot started");
}

void BulletController::setVisibilityForBullets() {
    int count = 0;
    for (int i = 0; i < bulletsNumber; i++) {
        int randomValue = mutRandomizer->nextInt(100);
        if (randomValue <= BULLETS_PART_TO_BE_RENDERED_IN_PERCENTS) {
            bullets[i].activateForTime(1, 1000);
            count++;
        }
    }
    Logger::debug(std::to_string(count) + " bullets will be visible by this shot");
}

void BulletController::makeExplosion(int numberOfBullet) {
    shotNumberToBeDeleted = numberOfBullet;
    fightersController->handleAttack();
}

Shot.h的部分:

#pragma once
#include <SDL.h>
#include "Logger.h"
#include <string>

class Shot
{

public:
    Shot(int timeBeforeStart);
    ~Shot();
    void update();
    static const int WAIT_FOR_SHOT_START = 0;
    static const int BULLET_LEFT_WEAPON = 1;
    static const int BULLET_IN_ATTACK_ZONE = 2;
    bool isInHitZone();

private:
    const int SHOT_TIME = 750;
    int statement;
    unsigned long int startShotTime;
    unsigned long int endShotTime;
    int bulletNumber;
};

Shot.cpp的部分:

#include "Shot.h"

static int bulletCount = 0;



<details>
<summary>英文:</summary>

In my code I create 3 shots after the user presses *ENTER*. There are delays `int NEXT_SHOT_IN_CHAIN_DELAY` between each other. When the *ENTER* is pressed I create three objects of class `Shot` and add them in the vector `std::vector &lt;Shot*&gt; shots`. The class `Shot` changes the inside statement from: 0 to 2 

**WAIT_FOR_SHOT_START** -&gt;  **BULLET_LEFT_WEAPON** -&gt; **BULLET_IN_ATTACK_ZONE** 

According to the current time from the start of the program, when I create an exemplar of the `class shot` - the number of the bullet and the start time to leave the weapon (variable  `startShotTime`) has normal values. 

Console **output**:
DEBUG: Bullet by creation: 0; Start shot time: 3833; End shot time: 4583 and statement: 0; Actual time: 4583
DEBUG: Bullet by creation: 1; Start shot time: 4163; End shot time: 4913 and statement: 0; Actual time: 4913
DEBUG: Bullet by creation: 2; Start shot time: 4493; End shot time: 5243 and statement: 0; Actual time: 5243

On every frame I update all the shots. And in the updating function my logger tells me that the bulletNumber and startShotTime have already new (*strange*) values. 
Console **output**:
DEBUG: Bullet 258744461 Start shot time: 575665160
DEBUG: Bullet 575663496 Start shot time: 3744914323
DEBUG: Bullet 575663688 Start shot time: 575663624

What can change the values of my private variables? 
Class Bullet is only the graphic demonstration of the bullets on the screen. It does&#39;n affect the `Shot class`.
If it&#39;s important: I use **VisualStudio** on Windows 10 and **SDL2** library. 
Here is my code, `BulletController.h`:
#pragma once
#include &lt;vector&gt;
#include &quot;Timer.h&quot;
#include &quot;Logger.h&quot;
#include &lt;vector&gt;
#include &quot;FightersController.h&quot;
#include &quot;Bullet.h&quot;
#include &quot;Random.h&quot;
#include &quot;Shot.h&quot;
#include &quot;EventsListener.h&quot;
class BulletController{
public:		 
BulletController(FightersController* fightersController, Bullet *bullets, int bulletsNumber);
~ BulletController();		 
void update(long deltaTime);
private:
int bulletsNumber;
const int BULLETS_PART_TO_BE_RENDERED_IN_PERCENTS = 60;
Bullet* bullets;
FightersController* fightersController = nullptr;			
const int NOTHING_TO_DELETE =-1;
std::vector &lt;Shot*&gt; shots;		
int shotNumberToBeDeleted=NOTHING_TO_DELETE ;		
void makeExplosion(int numberOfBullet);	
void updateShooting();
void startToShotIfPossible();
void updateActualBullets();
void setVisibilityForBullets();
const int bulletsInLine = 3;
const int NEXT_SHOT_IN_CHAIN_DELAY = 330;
bool shotAlreadyPressed;
//Mutable
Random* mutRandomizer;
};

`BulletController.cpp`:
#include &quot;BulletController.h&quot;
BulletController::BulletController(FightersController* fightersController, Bullet *bullets, int bulletsNumber){
this-&gt;bullets = bullets;
this-&gt;bulletsNumber = bulletsNumber;
this-&gt;fightersController = fightersController;	
mutRandomizer = new Random();
}
BulletController::~BulletController(){
delete mutRandomizer;	
delete bullets;
}
void BulletController::update(long deltaTime){
updateActualBullets();
updateShooting();	
}
void BulletController::updateShooting() {	
std::vector &lt;Command&gt;* commands = EventsListener::getInstance()-&gt;getCommands();
bool shotCommandFounded = false;
if (commands-&gt;size() &gt; 0) {				
for (auto i = (commands-&gt;begin()); i != commands-&gt;end(); ++i) {
Command command = (Command)*i;	//This copies the command
if (command.getType() == command_constants::SHOT) {
Logger::debug(&quot;Player pressed shot&quot;);
if (!shotAlreadyPressed) {
shotAlreadyPressed = true;
startToShotIfPossible();
}
shotCommandFounded = true;
}	
}		
}
if (shotAlreadyPressed) {
if (!shotCommandFounded) {
shotAlreadyPressed = false;
}
}
}
void BulletController::updateActualBullets() {		
if (shots.size() &gt; 0) {
int toBeDeleted = -1;		
int itterator = 0;
for (auto i : shots) {
i-&gt;update();
}		
for (auto i : shots) {			
if (i-&gt;isInHitZone()) {
makeExplosion(itterator);
toBeDeleted = itterator;
}
itterator++;
}		
if (toBeDeleted &gt;= 0) {			
shots.erase(shots.begin() + toBeDeleted);	
}
}	
}
void BulletController::startToShotIfPossible() {	
Shot firstShot(0);
shots.push_back(&amp;firstShot);
Shot secondShot(NEXT_SHOT_IN_CHAIN_DELAY);
shots.push_back(&amp;secondShot);
Shot thirdShot(NEXT_SHOT_IN_CHAIN_DELAY*2);
shots.push_back(&amp;thirdShot);
setVisibilityForBullets();
Logger::debug(&quot;Shot started&quot;);	
}
void BulletController::setVisibilityForBullets() {
int count = 0;
for (int i = 0; i &lt; bulletsNumber; i++) {
int randomValue = mutRandomizer-&gt;nextInt(100);
if (randomValue &lt;= BULLETS_PART_TO_BE_RENDERED_IN_PERCENTS) {
bullets[i].activateForTime(1, 1000);
count++;
}
}
Logger::debug(std::to_string(count) + &quot; bullets will be visible by this shot&quot;);
}
void BulletController::makeExplosion(int numberOfBullet){
shotNumberToBeDeleted = numberOfBullet;
fightersController-&gt;handleAttack();
}

`Shot.h`:
#pragma once
#include &lt;SDL.h&gt;
#include &quot;Logger.h&quot;
#include &lt;string&gt;
class Shot
{
public:
Shot(int timeBeforeStart);	
~Shot();	
void update();
static const int WAIT_FOR_SHOT_START = 0;
static const int BULLET_LEFT_WEAPON = 1;
static const int BULLET_IN_ATTACK_ZONE = 2;
bool isInHitZone();
private:
const int SHOT_TIME = 750;	
int statement;	
unsigned long int startShotTime;
unsigned long int endShotTime;	
int bulletNumber;		
};
`Shot.cpp`:
#include &quot;Shot.h&quot;
static int bulletCount = 0;
Shot::Shot(int timeBeforeStart) {
bulletNumber = bulletCount;
bulletCount++;
startShotTime = SDL_GetTicks() + timeBeforeStart;
endShotTime = SDL_GetTicks() + timeBeforeStart + SHOT_TIME;	
statement = WAIT_FOR_SHOT_START;	
Logger::debug(&quot;Bullet by creation: &quot; + std::to_string(bulletNumber) + &quot;; Start shot time: &quot; + std::to_string(startShotTime) + &quot;; End shot time: &quot; + std::to_string(endShotTime) + &quot; and statement: &quot; + std::to_string(statement) + &quot;; Actual time: &quot; + std::to_string(endShotTime));
}
Shot::~Shot() {
}
void Shot::update() {
Logger::debug(&quot;Bullet &quot; + std::to_string(bulletNumber) + &quot; Start shot time: &quot; + std::to_string(startShotTime));
if (statement == WAIT_FOR_SHOT_START) {
if (SDL_GetTicks() &gt;= startShotTime) {
statement == BULLET_LEFT_WEAPON;
Logger::debug(&quot;Bullet &quot; + std::to_string(bulletNumber) + &quot; left the weapon at &quot; + std::to_string(SDL_GetTicks()));
}
}
else if (statement == BULLET_LEFT_WEAPON) {
if (SDL_GetTicks() &gt;= endShotTime) {
statement == BULLET_IN_ATTACK_ZONE;
Logger::debug(&quot;Bullet &quot; + std::to_string(bulletNumber) + &quot; is in hit zone at &quot; + std::to_string(SDL_GetTicks()));
}
}
}
bool Shot::isInHitZone() {	
if (statement == BULLET_IN_ATTACK_ZONE) return true;
else return false;
}

</details>
# 答案1
**得分**: 1
> void BulletController::startToShotIfPossible() {    
>     Shot firstShot(0);
>     shots.push_back(&firstShot);
>     Shot secondShot(NEXT_SHOT_IN_CHAIN_DELAY);
>     shots.push_back(&secondShot);
>     Shot thirdShot(NEXT_SHOT_IN_CHAIN_DELAY*2);
>     shots.push_back(&thirdShot);
>     setVisibilityForBullets();
>     Logger::debug("Shot started");  
> } 
这个函数在当前堆栈帧中创建了三个 `Shot` 变量。它将这些变量的地址存储在 `shots` 向量中。
然而,一旦该函数退出,为该堆栈帧分配的内存可能会被重新使用,并且其他数据可能会被写入这些变量之前存在的地址。然而,您仍然保留了这些地址,尽管它们可能不再指向任何有效的数据。
这会导致[未定义行为](https://stackoverflow.com/questions/2397984/undefined-unspecified-and-implementation-defined-behavior)。
<details>
<summary>英文:</summary>
&gt;     void BulletController::startToShotIfPossible() {    
&gt;         Shot firstShot(0);
&gt;         shots.push_back(&amp;firstShot);
&gt;         Shot secondShot(NEXT_SHOT_IN_CHAIN_DELAY);
&gt;         shots.push_back(&amp;secondShot);
&gt;         Shot thirdShot(NEXT_SHOT_IN_CHAIN_DELAY*2);
&gt;         shots.push_back(&amp;thirdShot);
&gt;         setVisibilityForBullets();
&gt;         Logger::debug(&quot;Shot started&quot;);  
&gt;     }
This function creates three `Shot` variables in the current stackframe. It stores the addresses of those variables in the `shots` vector.
However, the memory allotted for that stackframe may be reused once that function exits, and other data may be written at the addresses where those variables previously existed. However, you still have those addressed stored, even though they may no longer point to any valid data.
This leads to [undefined behavior](https://stackoverflow.com/questions/2397984/undefined-unspecified-and-implementation-defined-behavior).
</details>

huangapple
  • 本文由 发表于 2023年7月20日 15:18:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/76727513.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定