У меня проблема с объявлением 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.
Соответствующий код для сбоя ->
.час
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);
};
Пример кода ->
.час
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
прежде чем он будет создан, это поставить точку останова внутри конструктора. Исходя из приведенного выше кода, мы не можем быть уверены, что класс создается только один или несколько раз (из других мест).
Также вы уверены, что не звоните Draw
или же LookHook
прежде чем создавать my_log2
объект. Опять же, подобные вещи тривиальны для тестирования с помощью отладчика, но нам очень трудно сказать только часть кода в наших руках. На самом деле, так как вышеприведенная программа не имеет main
это не MCVE.
Если он действительно падает, когда вы создаете ExampleAppLog
объект, а не при попытке использовать его до того, как он был создан, тогда большая часть приведенного выше кода бесполезна и закомментирует код (и удалит его из вопроса), если он все-таки выйдет из строя, очень поможет людям помочь вам.
С другой стороны, если происходит сбой из-за того, что вы используете my_log2 до того, как он будет создан, то отсутствует необходимый код для воспроизведения проблемы.
Если проблема связана с порядком инициализации, то единственным решением может быть синглтон. Посмотрите на принятый ответ здесь: Как реализовать многопоточный безопасный синглтон в C ++ 11 без использования <мьютекс>.
В любом случае, вам трудно помочь, потому что вы не вкладываете достаточно усилий в свой вопрос. Помните, что если код не может быть легко скопирован и вставлен, почти никто не будет тратить время на создание проекта еще больше, когда очевидно, что отсутствуют важные строки или информация, потому что с предоставленной информацией, почти невозможно, чтобы он потерпел крах на указанная строка.
На самом деле, мы предполагаем, что main — это пустая функция и что нет другого глобального использования my_log2
указатель и ExampleAppLog
структура, то когда бы функция reserve
называться.
В качестве бонуса, если вы зададите хорошие вопросы, вы получите больше очков на сайте!
Других решений пока нет …