Search code examples
c++timec++-chrono

Lifetime of an object


I'm expecting a strange issue with object lifetime. I instantiated a struct in a scope (Beginning of the scope). This object is as follows :

struct Spy
{
    Spy(const std::string& p_name) : name(p_name) 
    { 
        start = std::chrono::steady_clock::now();
    }

    ~Spy() 
    { 
        Destroy();
    }

    void Destroy()
    {
        end = std::chrono::steady_clock::now();
        Save();
    }

    std::string name;
    std::chrono::steady_clock::time_point start;
    std::chrono::steady_clock::time_point end;

    void Save() { Profiler::Save(*this); }
};

The goal is to calculate the Spy lifetime, so the timer should start at the creation (Ctor) and the timer should stop and save data in another class on destroy (Dtor).

Here is the spy usage :

ElkTools::Utils::Profiler::Spy spy("PostUpdate");
if (m_enableRendering)
{
    m_windowManager->GetDriver()->ClearScreen();
    RenderScene();
    m_windowManager->GetDevice()->SwapBuffers();
}

m_inputManager->Update();
Context::Device::PollEvents();
spy.Destroy();

This code works well, but when I don't call the destroy method (That should get called by the dtor) the elapsed time (end - start) is very very low (0.0000001). Is it due to the compiler optimization ? Does the compiler detect that I don't invoke any method of this object so it destroy it from the stack ?

EDIT : Well, I got my answer. The problem was that I was using a macro to create the spy as follows :

#define PROFILER_SPY(name) \
  if (ElkTools::Utils::Profiler::__RUNNING) \
    ElkTools::Utils::Profiler::Spy __profiler_spy__(name)

But I totally forget that my if statement is a scope, so outside of the if the spy is destroyed..... Do you have any idea to keep checking the condition without destroying the spy at the if statement ?


Solution

  • std::optional or std::unique_ptr would be a reasonable fix for something like this.

    #define PROFILER_SPY(name) \
        std::optional<ElkTools::Utils::Profiler::Spy> __profiler_spy__ = \
            ElkTools::Utils::Profiler::__RUNNING
            ? std::make_optional<ElkTools::Utils::Profiler::Spy>(name)
            : std::nullopt
    

    Or with std::unique_ptr:

    #define PROFILER_SPY(name) \
        std::unique_ptr<ElkTools::Utils::Profiler::Spy> __profiler_spy__ = \
            ElkTools::Utils::Profiler::__RUNNING
            ? std::make_unique<ElkTools::Utils::Profiler::Spy>(name)
            : nullptr