How can i store a vector-list as a global variable?

Viewed 693

I am creating a tree that consists of branches. For the purpose of my work, I need to keep track of the branches, and In order to do that, I want to store them in a vector-list. I store the vector-list as a global variable in this file, as I want to use it in both the constructor and the function shown in the code snippet below.

The tricky part here is that I get an error message (running in Visual Studio 2013) that as far as I can tell has something to do with the iterator not doing its job properly. The error message appears whenever i call branchList.push_back(root) and branchList.resize(). branchList.size() does NOT result in an error.

So my question is: What am I missing / not understanding to make this work? If i were to place vector branchList; in the beginning of the constructor, everything works as intended. This however does not help me, since I need to also use it in other functions later on.

Relevant code snippets from the files I am using.

skeletonBuilder.h:

class TreeSkeleton {

public:
    TreeSkeleton();
    void growTree();
};

skeletonBuilder.cpp:

#include "skeletonBuilder.h"
#include <cstdint>
#include <vector>


typedef struct branch {
    branch *parent;
    vec3 position;
    vec3 direction;
} branch;

//used by constructor + "treeGrow" function
std::vector<branch> branchList = {};

TreeSkeleton::TreeSkeleton() {
    //instantiate the tree root as a starting position.
    branch root;
    root.parent = NULL;
    root.position = vec3(0, 0, 0);
    root.direction = vec3(0, 1, 0); 

    branchList.size(); //works fine
    branchList.resize(100); //Crashes here
    branchList.push_back(root); //Crashes here
}

TreeSkeleton::growTree() {
    //pushing more branches to branchList
}

main.cpp:

#include "skeletonBuilder.h"

TreeSkeleton tree;

int main(int argc, char *argv[]) {

    return 0;
}

The error message I am getting:

Unhandled exception at 0x00507077 in OpenGL_project_Debug.exe: 0xC0000005: Access violation reading location 0x40EAAAB4.

The error message takes me to the following code snippet in a file called "vector":

 #if _VECTOR_ORPHAN_RANGE
void _Orphan_range(pointer _First, pointer _Last) const
    {   // orphan iterators within specified (inclusive) range
    _Lockit _Lock(_LOCK_DEBUG);
    const_iterator **_Pnext = (const_iterator **)this->_Getpfirst();
    if (_Pnext != 0)
        while (*_Pnext != 0) //<----------------This is the row that it gets stuck on
            if ((*_Pnext)->_Ptr < _First || _Last < (*_Pnext)->_Ptr)
                _Pnext = (const_iterator **)(*_Pnext)->_Getpnext();
            else
                {   // orphan the iterator
                (*_Pnext)->_Clrcont();
                *_Pnext = *(const_iterator **)(*_Pnext)->_Getpnext();
                }
    }
1 Answers

The initialization order of global objects is not guaranteed between implementation files. There is no way to know rather the globals of main.cpp or skeletonBuilder.cpp will be initialized first. In your case, TreeSkeleton tree is initialized before std::vector<branch> branchList which leads to your problem. The constructor of TreeSkeleton must use the uninitialized branchList which is undefined behavior. The solution is to place your globals in such a way that the order is guaranteed.

One solution is to make branchList a local static variable. These variables are guaranteed to be initialized when first encountered.

For example :

class TreeSkeleton {

public:
    TreeSkeleton();
    void growTree();

private:
    static std::vector<branch> & getBranches();
};

std::vector<branch> & TreeSkeleton::getBranches()
{
    // branchList is initialized the first time this line is encountered
    static std::vector<branch> branchList;
    return branchList;
}

TreeSkeleton::TreeSkeleton() 
{
    //instantiate the tree root as a starting position.
    branch root;
    root.parent = NULL;
    root.position = vec3(0, 0, 0);
    root.direction = vec3(0, 1, 0);

    auto & branchList = getBranches();
    branchList.size();
    branchList.push_back(root); // Should be fine now
}
Related