C ++变量内容在2个函数之间丢失[虚幻]

时间:2019-03-17 18:08:44

标签: c++

问候程序员。

我一直在努力在虚幻引擎中学习c ++。我以为我知道如何在一个类中正确地跟踪时间,但是可惜我的变量正在两次调用之间将时间的内容更改为截然不同的数字。

对于上下文,存在少量对象:

  • 全球时间系统
    • 此类负责管理时间并从时间观察者接收更新时间。这也是一个单身人士!
  • TimeWatcher
    • 超级简单,只是我生成的一个Uobject,因此它可以接收来自引擎的更新滴答声并将它们传递到全球时间系统中
  • 时间课
    • 用于容纳小时,分钟和秒的班级。除此之外,如何使用它取决于开发人员使用该类。就我而言,我只是想存储它,从那以后删除它的时间以创建一个倒数计时器。

我们有自己的小型日志记录系统,可以帮助调试,主要是生成没有所有不真实内容的日志,并且采用我们喜欢的格式。该日志输出以下数据:

<Log, TimerSystem> [2] 2019.03.17-17.41.42: init attempt, init time should be: 23:6.0
<Log, TimerSystem> [3] 2019.03.17-17.41.42: init attempt succes, 23:6.0
<Log, TimerSystem> [6] 2019.03.17-17.41.42: Timer tick occured, lets see what our timer thinks about the time -225161083:32766:00

因此,由此我们可以解释为,在其中设置了作用域的变量(如下所示)已在此处正确设置。但是,当我们尝试再次在handleTick函数中读取该变量时,该变量是完全错误的。

InitTimer函数:

void GlobalTimerSystem::InitTimer(UWorld* world, Time* initialTime)
{

    DebugUtility::WriteLog("init attempt, init time should be: " + initialTime->ToString(), DebugUtility::Log, DebugUtility::TimerSystem);
    check(world);

    //create timeWatcher in the world
    FVector location(0.0f, 0.0f, 0.0f);
    FRotator rotation(0.0f, 0.0f, 0.0f);
    FActorSpawnParameters SpawnInfo;
    world->SpawnActor<ATimeWatcher>(location, rotation, SpawnInfo);
    //set current time to init value
    Time* trPointer = new Time(initialTime->GetHours(), initialTime->GetMinutes(), initialTime->GetSeconds());
    this->timeRemaining = *trPointer;
    DebugUtility::WriteLog("init attempt succes, " + timeRemaining.ToString(), DebugUtility::Log, DebugUtility::TimerSystem);
    }

我在这里做一些愚蠢的指针废话,部分原因是由于此时的绝望。

句柄刻度线功能:

void GlobalTimerSystem::HandleTimerTick(float deltaTime)
{
    DebugUtility::WriteLog("Timer tick occured, lets see what our timer thinks about the time " + timeRemaining.ToString(), DebugUtility::Log, DebugUtility::TimerSystem);
    ticksReceived++;
    FString debug2;
    debug2.Append("Ticks received: ");
    debug2.AppendInt(ticksReceived);
    DebugUtility::WriteLog(debug2, DebugUtility::Log, DebugUtility::TimerSystem);
    double t = static_cast<double>(deltaTime);
    DecreaseTimer(&t);
    if (deltaTime != NULL) {
        FString debug;
        debug.Append(TEXT("current time remaining is "));
        debug.Append(*timeRemaining.ToString());
        DebugUtility::WriteLog(debug, DebugUtility::Log, DebugUtility::TimerSystem);
    }
}

现在,我们一旦进入上述功能,便知道事情已经错了。出于良好的考虑,这里是此类的头文件。

class PGT_PROJECT_API GlobalTimerSystem
{
    friend class ATimeWatcher;
private:
    Time timeRemaining;
    Time timeElapsedNotPaused;
    Time timeElapsedPaused;
    UINT ticksReceived = 0;
    bool paused = false;
    bool initComplete = false;
    void HandleTimerTick(float deltaTime);
    static GlobalTimerSystem* timerSystem;

public:
    static GlobalTimerSystem* GetTimerSystem();

    void InitTimer(UWorld* world, Time* initialTime);
    void IncreaseTimer(double* additionalSeconds);
    void DecreaseTimer(double* removeSeconds);

    double GetTimeRemaining();
    double GetTimeElapsed();
    GlobalTimerSystem();
    ~GlobalTimerSystem();
};

如果需要更多信息,我将很乐意提供。谢谢您的时间!

编辑:

我正在超载Time :: operator =,它显示如下:

Time & Time::operator=(Time & t)
{
    _seconds = t._seconds;
    _minutes = t._minutes;
    _hours = t._hours;
    return *this;
}

并按如下方式使用它:

this->timeRemaining = Time(initialTime->GetHours(), initialTime->GetMinutes(), initialTime->GetSeconds());

但这会导致以下我不理解的编译器错误:

Path...\Private\GlobalTimerSystem.cpp(62) : error C4239: nonstandard extension used: 'argument': conversion from 'Time' to 'Time &'

1 个答案:

答案 0 :(得分:2)

GlobalTimerSystem::InitTimer(UWorld*, Time*)中,您需要执行以下操作:

Time* trPointer = new Time(initialTime->GetHours(),
                           initialTime->GetMinutes(),
                           initialTime->GetSeconds());
this->timeRemaining = trPointer;

这意味着:

  • heap上创建类型为new的{​​{1}}对象,使用以下参数构造它,一旦准备好,就返回指向它的指针(Time)我将其存储在本地变量Time*;
  • 将指针trPointer的值(这是我们刚刚在堆上分配并初始化的类trPointer实例的地址)分配给我的实例变量Time(它是类timeRemaining实例)。

因此,一旦您到达TimeGlobalTimerSystem::HandleTimerTick就会包含垃圾,当翻译this->timeRemaining时它会保留垃圾(因此{{1 }} 你看)。此外,您现在为您创建的ToString实例在堆上分配的内存被浪费了,因为您将永远不会释放它,甚至不会使用它。

问题是,在这种情况下,您根本不需要堆!

取决于-225161083:32766:00的行为方式(您说过过载),您应该能够做到:

Time

这将创建一个临时operator=实例,并使用传递的参数对其进行初始化,然后在实例变量this->timeRemaining = Time(initialTime->GetHours(), initialTime->GetMinutes(), initialTime->GetSeconds()); 中“复制”(Time)。如果这样做,您可能想研究=,因为“临时timeRemaining实例”是一个右值。请注意,在这种情况下,我们不会泄漏内存,因为所有内容都是在stack上分配的,并且会在函数返回时释放。

如果这不起作用,则意味着Time::operator=(Time&&)的行为不正确,应予以修复。另一种方法是手动设置Time的小时,分​​钟和秒字段(如果它们是Time::operator=timeRemaining)或(好得多),以使用诸如{{ 1}}允许您public

最后,再次取决于friend的内部结构和Time::set(/*hours, minutes, seconds*/)的编写方式,请注意this->timeRemaining->set(...)本身就是Time,即“临时中间{{ 1}}实例”,甚至不需要,这样就可以简化和可读得多

Time::operator=

结论是,我相信您的问题来自initialTime的实现。