简体   繁体   中英

Unspecified behaviour of std::vector with pointer to object

I have found nerve wracking issue which I seem to be unable to solve.

SceneSettings::SceneSettings()
{
    unsigned int w = (ConfigurationManager::GetInstance().GetWidth() >> 1) - 80;
    unsigned int h = (ConfigurationManager::GetInstance().GetHeight() >> 1) - 50;

    std::vector< std::string > menu_items;

    menu_items.push_back("Graphic Settings");
    menu_items.push_back("Sound Settings");
    menu_items.push_back("Game Settings");
    menu_items.push_back("Back");

    Label* aux = NULL;
    for ( unsigned int i = 0; i < menu_items.size(); i++ )
    {
        aux = new Label(menu_items[i], w, h);
        items.push_back(aux);
        aux = NULL;

        aux = new Label(menu_items[i], w, h);
        aux->SetColor(255, 0, 0);

        hover_section.push_back(aux);
        hover.push_back(false);

        aux = NULL;
        h += 25;
    }
}

SceneSettings::~SceneSettings()
{
    for (unsigned int i = 0; i < items.size(); i++)
    {
        delete items[i];
        delete hover_section[i];
    }

    items.clear();
    hover_section.clear();
}

void SceneSettings::Draw()
{
    for ( unsigned int i = 0; i < items.size(); i++ )
    {
        if (hover[i])
            hover_section[i]->Draw();
        else
            items[i]->Draw();
    }
}

void SceneSettings::HandleEvents(SDL_Event& event)
{
    switch(event.type)
    {
        case SDL_MOUSEMOTION :
        {
            int x = event.motion.x;
            int y = event.motion.y;

            for ( unsigned int i = 0; i < items.size(); i++ )
                hover[i] = items[i]->GetIsInLabel(x, y);
        } break;
    }
}

Now what it does is, that first label "Graphic Settings" is not displayed. (not invisible, just plainly not visible)

items are defined as:

std::vector< Label* > items;
std::vector< Label* > hover_section;
std::vector< bool > hover;

For some reason it doesnt work, however in another scene ("main_menu") I have identical vector of labels (only captions are different) which works ok.

Now this one is more interesting that it seems. Since not only does it not display first item, but it displays 1st hover item even if mouse is completely out its range.

If I replace std::vector for direct Label* menu_item_1 in SceneSettings header, it displays correctly. Which leads me to think its connected to std::vector

One more thing I don't quite understand is, that if I run it in debug mode and going by steps, it displays correctly, however neither watches nor call stack does show anything unusual.

Any help is appreciated.

If you are passing SceneSettings objects by value anywhere, either as arguments to functions or returning such objects, then you definitely need to consider your use of pointers in the vectors, or have to implement a copy-constructor and a copy-assignment operator (as told by the rule of three).

The default functions created by the compiler will only do shallow copying, ie it copies the vectors and the pointers, it doesn't create new pointers (deep copying). That leads to you having two objects both containing pointers to the same objects in the vectors, and if one object is destructed if will free the memory, leaving the other object with stray pointers and that will lead to undefined behavior.

It turns out the problem was in Label class, in which I neglected to initialize texture and buffer ids for GLSL. Adding initial values (0) to them in Label constructor fixed the problem.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM