在两个 .cpp 文件之间定义全局 class/struct 指针

Defining global class/struct pointer between two .cpp files

我在不同的 .cpp 文件之间声明 public/extern 结构对象时遇到问题。我正在尝试使用 imgui 记录器从钩子中记录一些消息。

程序将在 ExampleAppLog my_log2; -> ImGuiTextBuffer Buf; -> class ImVector -> if (Data)

崩溃

因为我在一个 .cpp 中执行此操作 ExampleAppLog* my_log2 = new ExampleAppLog();,其中包含包含 .h 的 struct ExampleAppLog,以及 my_log2 的声明。

相关代码崩溃-> .h

struct ExampleAppLog
    {
        ImGuiTextBuffer     Buf;
    }
extern ExampleAppLog* my_log2;

.cpp

 #include ".h"
 ExampleAppLog* my_log2 = new ExampleAppLog(); //this line make it crash

imgui.h

struct ImGuiTextBuffer
{
    ImVector<char>      Buf;
}

class ImVector
{
public:
    int                         Size;
    int                         Capacity;
    T*                          Data;

    typedef T                   value_type;
    typedef value_type*         iterator;
    typedef const value_type*   const_iterator;

    ImVector()                  { Size = Capacity = 0; Data = NULL; }
    ~ImVector()                 { if (Data) ImGui::MemFree(Data); }

    inline bool                 empty() const                   { return Size == 0; }
    inline int                  size() const                    { return Size; }
    inline int                  capacity() const                { return Capacity; }

    inline value_type&          operator[](int i)               { IM_ASSERT(i < Size); return Data[i]; }
    inline const value_type&    operator[](int i) const         { IM_ASSERT(i < Size); return Data[i]; }

    inline void                 clear()                         { if (Data) { Size = Capacity = 0; ImGui::MemFree(Data); Data = NULL; } }
    inline iterator             begin()                         { return Data; }
    inline const_iterator       begin() const                   { return Data; }
    inline iterator             end()                           { return Data + Size; }
    inline const_iterator       end() const                     { return Data + Size; }
    inline value_type&          front()                         { IM_ASSERT(Size > 0); return Data[0]; }
    inline const value_type&    front() const                   { IM_ASSERT(Size > 0); return Data[0]; }
    inline value_type&          back()                          { IM_ASSERT(Size > 0); return Data[Size-1]; }
    inline const value_type&    back() const                    { IM_ASSERT(Size > 0); return Data[Size-1]; }
    inline void                 swap(ImVector<T>& rhs)          { int rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; int rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; value_type* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; }

    inline int                  _grow_capacity(int size) const  { int new_capacity = Capacity ? (Capacity + Capacity/2) : 8; return new_capacity > size ? new_capacity : size; }

    inline void                 resize(int new_size)            { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; }
    inline void                 resize(int new_size, const T& v){ if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) Data[n] = v; Size = new_size; }
    inline void                 reserve(int new_capacity)
    {
        if (new_capacity <= Capacity) return;
        T* new_data = (value_type*)ImGui::MemAlloc((size_t)new_capacity * sizeof(T));
        if (Data) //here is the crash. Data is 0x000000000 when crashing
            memcpy(new_data, Data, (size_t)Size * sizeof(T));
        ImGui::MemFree(Data);
};

示例代码 -> .h

struct ExampleAppLog
{
    ImGuiTextBuffer     Buf;
    ImGuiTextFilter     Filter;
    ImVector<int>       LineOffsets;        // Index to lines offset
    bool                ScrollToBottom;

    void    Clear() { Buf.clear(); LineOffsets.clear(); }

    void    AddLog(const char* fmt, ...) IM_FMTARGS(2)
    {
        int old_size = Buf.size();
        va_list args;
        va_start(args, fmt);
        Buf.appendv(fmt, args);
        va_end(args);
        for (int new_size = Buf.size(); old_size < new_size; old_size++)
            if (Buf[old_size] == '\n')
                LineOffsets.push_back(old_size);
        ScrollToBottom = true;
    }

    void    Draw(const char* title, bool* p_open = NULL)
    {
        ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver);
        ImGui::Begin(title, p_open);
        if (ImGui::Button("Clear")) Clear();
        ImGui::SameLine();
        bool copy = ImGui::Button("Copy");
        ImGui::SameLine();
        Filter.Draw("Filter", -100.0f);
        ImGui::Separator();
        ImGui::BeginChild("scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar);
        if (copy) ImGui::LogToClipboard();

        if (Filter.IsActive())
        {
            const char* buf_begin = Buf.begin();
            const char* line = buf_begin;
            for (int line_no = 0; line != NULL; line_no++)
            {
                const char* line_end = (line_no < LineOffsets.Size) ? buf_begin + LineOffsets[line_no] : NULL;
                if (Filter.PassFilter(line, line_end))
                    ImGui::TextUnformatted(line, line_end);
                line = line_end && line_end[1] ? line_end + 1 : NULL;
            }
        }
        else
        {
            ImGui::TextUnformatted(Buf.begin());
        }

        if (ScrollToBottom)
            ImGui::SetScrollHere(1.0f);
        ScrollToBottom = false;
        ImGui::EndChild();
        ImGui::End();
        }
    }; 


extern ExampleAppLog* my_log2;

One.cpp

#include ".h"
        ExampleAppLog* my_log2 = new ExampleAppLog(); //this line make it crash

       void LogHook(const char* Info)
    {
        my_log2->AddLog(Info);
    }

Two.cpp

#include ".h"
    bool bDraw = true;
    void Draw()
    {
      my_log2->Draw("Logger", &bDraw);
    }

我尝试了很多不同的方法,但在尝试在多个 .cpp 中共享一个外部对象时,如果没有崩溃,我就不走运了。

记录器文档。

static ExampleAppLog my_log; //have tryd this but with extern etc. It still crash at the same place whan trying to share it globaly. If i do it all in one .cpp out sharing it publicly the code work
[...]
my_log.AddLog("Hello %d world\n", 123);
[...]
my_log.Draw("title");

很难告诉您您的问题是什么,因为缺少重要信息。

  • 您确定它在检查 Data 是否为空指针时崩溃了吗?
  • 您是否检查过 this 在崩溃时是否有效?
  • 你有没有在构造函数上打断点,看看什么时候调用的。

虽然看起来您没有制作这些对象的任何副本,但如果没有适当的支持,最好通过删除复制和移动构造函数和赋值运算符来阻止它。有关详细信息,请参阅 https://en.cppreference.com/w/cpp/language/function#Deleted_functions

查看问题是否是您在创建 ExampleAppLog 的函数之前调用它的一个明显方法是在构造函数中放置一个断点。从上面的代码中,我们无法确定 class 是只创建一次还是多次(从其他地方创建)。

此外,您确定在创建 my_log2 对象之前没有调用 DrawLookHook。同样,这种事情用调试器测试是微不足道的,但我们很难用手中的部分代码来判断。事实上,由于上​​面的程序没有 main,它不是 MCVE。

如果它真的在创建 ExampleAppLog 对象时崩溃,而不是在创建之前尝试使用它时崩溃,那么上面的大部分代码都是无用的并且注释掉代码(并将其从问题中删除) 如果它仍然崩溃,将极大地帮助人们帮助你。

另一方面,如果它因为您在创建它之前使用 my_log2 而崩溃,则说明缺少重现该问题所需的一些代码。

如果问题与初始化顺序有关,那么单例可能是解决方案。在此处查看已接受的答案:How to implement multithread safe singleton in C++11 without using <mutex>.

不管怎么说,都很难帮到你,因为你的问题不够用心。请记住,如果代码不能轻易复制和粘贴,几乎没有人会花更多的时间来创建项目,因为很明显缺少重要的行或信息,因为根据提供的信息,它几乎不可能崩溃指定行。

事实上,我们假设 main 是一个空函数,并且 my_log2 指针和 ExampleAppLog 结构没有其他全局用法,那么函数 reserve 被调用。

作为奖励,如果您提出好的问题,您会在网站上获得更多积分!