我在声明不同.cpp文件之间的public / extern结构对象时遇到问题。我正在尝试使用imgui记录器从挂钩中记录一些消息。
程序将在ExampleAppLog my_log2; -> ImGuiTextBuffer Buf; -> class ImVector -> if (Data)
上崩溃
因为我是在.cpp中执行此ExampleAppLog* my_log2 = new ExampleAppLog();
的工作,因此其中包含一个包含.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中共享一个extern对象,它最终会崩溃。
记录器文档。
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");
答案 0 :(得分:0)
由于缺少重要信息,很难告诉您问题出在哪里。
Data
是否为空指针时崩溃吗? this
在崩溃时是否有效? 虽然您似乎没有对这些对象进行任何复制,但是如果不能通过删除复制并移动构造函数和赋值运算符来提供适当的支持,则最好防止该复制。有关更多信息,请参见https://en.cppreference.com/w/cpp/language/function#Deleted_functions。
一种明显的查看问题的方法是在创建ExampleAppLog
之前调用一个函数,即在构造函数中放置一个断点。从上面的代码中,我们无法确定该类是仅一次创建还是多次创建(从其他位置)。
您还确定在创建Draw
对象之前不要调用LookHook
或my_log2
。再说一遍,用调试器进行测试是一件很简单的事情,但是对于我们来说,只用部分代码很难讲。实际上,由于上述程序没有main
,因此它不是MCVE。
如果创建ExampleAppLog
对象时确实崩溃了,而不是在创建对象之前尝试使用它,那么上面的大多数代码是无用的,并且注释掉了代码(并将其从问题中删除),如果它仍然崩溃,将极大地帮助人们为您提供帮助。
另一方面,如果由于在创建my_log2之前使用了my_log2而导致崩溃,则缺少一些重现此问题所需的代码。
如果问题与初始化顺序有关,则可能是单例。在此处查看已接受的答案:How to implement multithread safe singleton in C++11 without using <mutex>。
在任何情况下,都很难为您提供帮助,因为您在问题上的投入不足。请记住,如果无法轻松地复制和粘贴代码,则在明显缺少重要的行或信息的情况下,几乎没有人会花更多的时间来创建项目,因为有了所提供的信息,它几乎不可能崩溃。指定的行。
实际上,我们假设main是一个空函数,并且my_log2
指针和ExampleAppLog
结构都没有其他全局用法,那么函数reserve
何时会成为叫。
作为奖励,如果您提出好的问题,则可以在网站上获得更多积分!