Определение глобального указателя класса / структуры между двумя файлами .cpp - PullRequest
0 голосов
/ 08 сентября 2018

У меня проблема с объявлением public / extern struct object между различными файлами .cpp. Я пытаюсь использовать imgui logger для регистрации некоторых сообщений с помощью ловушки.

Сбой программы на ExampleAppLog my_log2; -> ImGuiTextBuffer Buf; -> class ImVector -> if (Data)

Потому что я делаю это ExampleAppLog* my_log2 = new ExampleAppLog(); внутри .cpp, в котором есть include .h со структурой 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");

1 Ответ

0 голосов
/ 09 сентября 2018

Трудно сказать, в чем ваша проблема, потому что отсутствует важная информация.

  • Вы уверены, что произошел сбой при проверке, является ли Data нулевым указателем?
  • Вы проверили, действительно ли this в момент сбоя?
  • Поставили ли вы точку останова на конструктор, чтобы увидеть, когда он вызывается.

Хотя похоже, что вы не делаете никаких копий этих объектов, было бы неплохо предотвратить это, если это не поддерживается должным образом, путем удаления конструктора копирования и перемещения и операторов присваивания. См. https://en.cppreference.com/w/cpp/language/function#Deleted_functions для получения дополнительной информации.

Один очевидный способ проверить, заключается ли проблема в том, что вы вызываете функцию ExampleAppLog до ее создания, - это поместить точку останова в конструктор. Исходя из приведенного выше кода, мы не можем быть уверены, что класс создается только один или несколько раз (из других мест).

Также вы уверены, что не вызываете Draw или LookHook до создания my_log2 объекта. Опять же, подобные вещи тривиальны для тестирования с помощью отладчика, но нам очень сложно сказать только часть кода в наших руках. На самом деле, так как вышеприведенная программа не имеет main, это не MCVE.

Если он действительно дает сбой при создании объекта ExampleAppLog, а не при попытке использовать его до того, как он был создан, то большая часть приведенного выше кода бесполезна и комментирует код (и удаляет его из вопроса), если он все еще крушение, очень помогло бы людям помочь вам.

С другой стороны, если происходит сбой из-за того, что вы используете my_log2 до того, как он будет создан, то отсутствует необходимый код для воспроизведения проблемы.

Если проблема связана с порядком инициализации, то решение может быть синглтоном. Посмотрите на принятый ответ здесь: Как реализовать многопоточный безопасный синглтон в C ++ 11 без использования .

В любом случае вам трудно помочь, потому что вы не уделяете достаточного внимания своему вопросу. Помните, что если код не может быть легко скопирован и вставлен, почти никто не будет тратить время на создание проекта еще больше, когда очевидно, что отсутствуют важные строки или информация, потому что с предоставленной информацией почти невозможно, чтобы он потерпел крах на указанная строка.

Фактически, мы предполагаем, что main - это пустая функция и что нет другого глобального использования ни my_log2 указателя, ни ExampleAppLog struct, тогда когда будет вызвана функция reserve.

В качестве бонуса, если вы зададите хорошие вопросы, вы получите больше очков на сайте!

...