-2

I have a problem declaring a public/extern struct object between different .cpp files. I am trying to use the imgui logger to log some messages from a hook.

The program is going to crash on ExampleAppLog my_log2; -> ImGuiTextBuffer Buf; -> class ImVector -> if (Data)

Because i do this ExampleAppLog* my_log2 = new ExampleAppLog(); inside a .cpp that have a include .h with the struct ExampleAppLog in it, and a declaration of my_log2 .

Relevant code to crash -> .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);
};

Exsample code -> .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);
    }

I have tried many different methodes but no luck without it ending up crashing when trying to share a extern object in multiple .cpp.

Logger documentation.

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");
  • I was not able to reproduce the failure. Your code as given does not compile. The problem may be elsewhere than what was presented. – Eljay Sep 08 '18 at 16:06
  • You have imgui added to your project right. And what does your error say? @Eljay And the source compile fine for me. – whyamistilhereanddontwork Sep 08 '18 at 16:27
  • What more can i say @PasserBy I have explained, showed a example and told about what my problem is.... – whyamistilhereanddontwork Sep 08 '18 at 17:13
  • In what way does it "crash", what is the exact error message? People are asking for a [mcve] as it is easier for us to copy and paste your code into an ide, compile and run it to find the problem. If it takes more effort than that most won't bother. Also we generally find that when a poster leaves out "irrelevant" bits of code those are the bits of code that actually contain the problem. – Alan Birtles Sep 08 '18 at 17:24
  • You can easily C&P the code if you have imgui and you can clearly see how i use the "struct" if you use your eyes. :) @PasserBy – whyamistilhereanddontwork Sep 08 '18 at 17:28
  • If you think global variables are your problem then create a simple program with no dependencies which contains just global variables and see if that works. – Alan Birtles Sep 08 '18 at 17:29
  • We don't see your results and your example is bloated with unrelated stuff. Read [mcve] again. – Passer By Sep 08 '18 at 17:30
  • I'm not going to start installing new software to debug your problem for you, even if I do, I imagine imgui still needs `#include`s, i.e. your code isn't a [mcve] – Alan Birtles Sep 08 '18 at 17:30
  • hold one @AlanBirtles. Wait a bit and i show some more. I have tryd before to post this queastion sins i have had this problem for 2 weeks now, and in my last post i showed all the code that was relevant to the crash and it ended up to get sett on hold becouse it was to mutch code and that the code was irelevant (even if that showed the location of the crash and code to show what was going on). – whyamistilhereanddontwork Sep 08 '18 at 17:36
  • If you want to try out the code download imgui source https://github.com/ocornut/imgui by clicking the clone and download button. Than go into the exsample folder and open the project. Than you add the code and compile... :D @AlanBirtles – whyamistilhereanddontwork Sep 08 '18 at 17:39
  • 1
    I idea of the "minimal" part of the "mcve" is that you delete irrelevant bits of code until the program stops crashing then the code that is left is the code that actually contains the problem. E.g. if the code is crashing on `Buf.begin()` in `Draw()` then you could delete everything else from `Draw()` does it still crash? If your question is put on hold then edit that question to get it re-opened rather than asking a new question. – Alan Birtles Sep 08 '18 at 17:40
  • @AlanBirtles `if(Data) Data = 0x0000000000000000` call stack (debuging) -> 1) `ImVector::reserve(int new_capacity) Line 960 C++` 2) `ExampleAppLog::ExampleAppLog() C++` 3) `dynamic initializer for 'my_log2''() Line 2 C++` my_log2 is also `0x0000000000000000` – whyamistilhereanddontwork Sep 08 '18 at 17:57
  • Do you really call `ExampleAppLog* my_log2 = new ExampleAppLog();` before `main()`. I would think that you have a problem with initialization order. Also, as others suggested remove any code that do not contribute to the problem including function and members. – Phil1970 Sep 08 '18 at 18:12
  • @Phil1970 see edit :D Thank you for taking your time :D – whyamistilhereanddontwork Sep 08 '18 at 18:24

1 Answers1

0

It is hard to tell you what your problem is because important information is missing.

  • Are you sure that it crash while checking if Data is a null pointer?
  • Have you checked if this is valid at the point of crash?
  • Have you put a breakpoint on the constructor to see when it was called.

While it looks like you don't make any copy of those objects, it would be a good idea to prevent it if not properly supported by deleting copy and move constructor and assignment operators. See https://en.cppreference.com/w/cpp/language/function#Deleted_functions for more information.

One obvious way to see if the problem is that you call a function of ExampleAppLog before it is created is to put a breakpoint inside the constructor. From the above code, we cannot be sure if the class is created only once or multiple times (from elsewhere).

Also are you sure that you don't call Draw or LookHook before you create my_log2 object. Again, that kind of thing is trivial to test with a debugger but very hard for us to tell with only part of the code in our hand. In fact, as the above program does not have a main, it is not a MCVE.

If it really crashes when you are creating ExampleAppLog object and not when trying to use it before it was created, then most of the code above is useless and commenting out code (and remove it from the question) if it still crash, would greatly help people to help you.

On the other hand, if it crash because you are using my_log2 before it is created, then some required code to reproduce the problem is missing.

If the problem is related to initialisation order, then a singleton might be the solution. Look at the accepted answer here: How to implement multithread safe singleton in C++11 without using <mutex>.

In any case, it is hard to help you because you don't put enough effort in your question. Remember that if the code cannot easily be copied and paste, almost nobody will take the time to create a project even more when it is obvious that important lines or information are missing because with the provided information, it is almost impossible that it crash on the specified line.

In fact, in we assume that main is an empty function and that there are no other global usage of either my_log2 pointer and ExampleAppLog struct, then when would the function reserve be called.

As a bonus, if you ask good questions, you get more points on the site!

Phil1970
  • 2,187
  • 2
  • 12
  • 12
  • This solved my problem :D Thank you. Keep up the good work :D https://stackoverflow.com/questions/11711920/how-to-implement-multithread-safe-singleton-in-c11-without-using-mutex <3 <3 <3 <3 <3 <3 <3 <3 But is it bad using this methode? :D <3 – whyamistilhereanddontwork Sep 09 '18 at 08:38