【问题标题】:I get an uninitialized object from a pointer我从指针中得到一个未初始化的对象
【发布时间】:2018-07-19 17:43:44
【问题描述】:

所以我在获取使用 SFML 形状的指针时遇到了一些麻烦。我不确定这是否与 SFML 有关,或者我做错了什么。

在 Draw() x(a ControlWindow) 中不包含有效值,它只显示“???”,如下所示。但是 m_controls(map) 包含控件对象的正确值。

我对 C++ 很陌生,因此非常感谢任何帮助。

异常

Exception thrown at 0x60B26EE5 (sfml-graphics-2.dll) in OokiiUI.exe: 0xC0000005: Access violation reading location 0x00000000.

主要

vector<WindowControl> windowControls;

void Draw ();

int main ()
{
    RectangleShape rect(Vector2f(120,120));
    WindowControl windowControl(nullptr,0);
    Control testControl(&windowControl,1);

    testControl.SetShape(&rect);

    windowControl.AddControl(testControl);
    windowControls.push_back(windowControl);


    return 0;
}

窗口控件

class WindowControl : Control
{
public:
    WindowControl ( WindowControl * windowControl, uint64_t uint64 )
        : Control ( windowControl, uint64 )
    {
    }

    void AddControl(Control control)
    {
        m_controls.insert_or_assign(control.GetId(), control);
        m_controlPtrs.push_back(&control);
    }

    vector<Control*>* GetControls()
    {
        return &m_controlPtrs;
    }

private:
    map<uint64_t, Control> m_controls;
    vector<Control*> m_controlPtrs;
};

for (auto x : windowControls)
{
    vector<Control*> *controlPtrs = x.GetControls();
    window->draw(x.GetControl(0)->GetShape());
}

【问题讨论】:

  • 这可能是由于您复制对象而不是将该指针添加到向量造成的。该本地对象超出范围,并且您的指针错误:仅供参考m_controlPtrs.push_back(&amp;control); 是错误的

标签: c++ pointers sfml


【解决方案1】:

您的问题是您将局部变量的指针添加到您的m_controlPtrs

void AddControl(Control control)
{
    m_controlPtrs.push_back(&control);
}

在此处获取Control 的副本,然后将其地址添加到您的vector 中。函数返回的那一刻,您的对象超出范围,并且该内存指向未初始化的垃圾。

您可能想要更新AddControl 以获取Control&amp;

@ShadowRanger raises a good point in the comments:我提到的可能会无限期地解决您的问题,但您的设计仍然不是很好。任何时候你有一个不会超过m_controlPtrsControl,你就会遇到同样的问题。你的代码现在很小,但这最终可能会变成一场噩梦。您可能应该改为更新 m_controlPtrs 以共享(或取得)Control 的所有权,这样就不会发生此问题。

最简单的方法是将m_controlPtrs 声明为std::vector&lt;std::shared_ptr&lt;Control&gt;&gt;,但这是应该考虑的事情。

【讨论】:

  • 虽然采用Control&amp; 只是意味着结果指针基于具有生命周期的不同对象,但vector 无法控制。除非你知道所有这些Controls 的范围总是比持有它们的WindowControl 长,否则你还没有解决问题,只是延迟了它。似乎转移了Control 的所有权(所以vector 存储Control,而不是Control*),或者使用shared_ptr(所以创建者和vector&lt;shared_ptr&lt;Control&gt;&gt; 共享所有权并且生命周期只要需要它),会是更好的选择。
【解决方案2】:

这里有问题:

void AddControl(Control control)
{
    m_controls.insert_or_assign(control.GetId(), control);
    m_controlPtrs.push_back(&control);
}

您添加参数control 的地址,该地址在函数结束时被销毁。看起来您想将添加到 map副本 的地址添加到您的 map,如下所示:

void AddControl(Control control)
{
    m_controls.insert_or_assign(control.GetId(), control);
    // don't use the parameter here, use the copy you put in the map
    m_controlPtrs.push_back(&m_controls[control.GetId()]); 
}

虽然这并不理想,因为如果您发送相同的control 两次,它只会在地图(更新)中出现一次,但在向量中出现两次指针。您可以使用从insert_or_update 返回的支付来解决这个问题:

void AddControl(Control control)
{
    auto [iter, was_inserted] = m_controls.insert_or_assign(control.GetId(), control);

    // only add to vector if it was not in the map before
    if(was_inserted)
        m_controlPtrs.push_back(&iter->second);
}

附注:

在这种情况下返回引用而不是指针更习惯:

vector<Control*>& GetControls()
{
    return m_controlPtrs;
}

这也破坏了封装,因此可能值得考虑如何避免如此直接地访问对象的内部。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-07
    • 2013-06-30
    • 2014-03-14
    • 1970-01-01
    • 2023-03-14
    • 2021-07-19
    • 1970-01-01
    相关资源
    最近更新 更多