Question

For example:

InitEmployee()
{
    vector<Employee> employeeList = {
        Employee("Clark Kent",0),
        Employee("Bruce Wayne",1),
        ...
        Employee("Hal Jordan",65535)
    }
}

I cannot query from file or DB as this program needs to be in a single executable so all the constant data must be hard coded. I'm actually using boost's multi_index_container for fast lookup by name and id but for simplicity sake I used vector here as example. The problem is that I cannot have that many (2^16) constant data in a single function without stack overflow. Are there any better ways initialize this list without splitting up the function?

I'm using VC12. Thanks!

Update

See chosen answer. As others have mentioned using static will force it to go on data rather than stack. This is what I ended up with:

InitEmployee()
{
    static Employee employeeList[] = {
        {"Clark Kent",0},
        {"Bruce Wayne",1},
        ...
        {"Hal Jordan",65535}
    }

    vector<Employee*> employeeVec;
    int count = sizeof(employeeList) / sizeof(Employee);
    for (int i = 0; i < count; i++)
    {
        employeeVec.emplace(&employeeList[i]);
    }
}

The thing was Employee class used a string class rather than c-string, so I didn't want two copies of it in memory. This way I end up with just the extra memory for pointers, which is still a lot but I believe this is the best option! Also works with multi_index_container! Thanks

Was it helpful?

Solution

Use a static array to store the initialization data.

InitEmployee()
{
    static char const* const names[] = {
        "Clark Kent",
        "Bruce Wayne",
        ...
        "Hal Jordan"
    };

    size_t const n = sizeof(names) / sizeof(*names);

    vector<Employee> employeeList;
    employeeList.reserve(n);
    for (size_t i=0; i<n; ++i)
        employeeList.emplace_back(names[i],i);
    ...
}

OTHER TIPS

Are you sure that too many string literals would cause stack overflow? Even if they would, you can try to put them in global scope:

const char *data = R"(
Clark Kent,0
Bruce Wayne,1
...
Hal Jordan,65535)"

/* ... */

int main()
{
    /* ... */
}

If it will compile fine with huge string literal, you can even try to use raw data from some DB file instead of list.

Since you're saying you're using VC 12, and you have one executable (and no data file) then place the hard-coded data within the resources, not the program code.

The resource that fits would be the RCDATA type. http://msdn.microsoft.com/en-us/library/windows/desktop/aa381039(v=vs.85).aspx

There are two options that spring to mind. The first depends on the version of Visual Studio. Are you using Visual Studio 2012, or version 12.0 (confusingly, VS2012 is actually 11.0). If you're using 2013 (ie 12.0) then you have the option of using the initializer lists which are new in C++11 (eg see the FAQ)

vector<Employee> employeeList = {
    {"Clark Kent",0},
    {"Bruce Wayne",1},
    ...
    {"Hal Jordan",65535}
};

Initializer lists rely on the C++11 rvalue move semantics to ensure that you only end up with one copy of the data in the application.

Another option could be to use boost::assign (see the docs) which means that you can use the same kind of syntax but do the allocation dynamically:

#include <boost/assign/std/vector.hpp> // for 'operator+=()'
using namespace boost::assign; // bring operator+= into scope
vector<Employee> employeeList;
employeeList += Employee("Clark Kent", 0),
                Employee("Bruce Wayne", 1), ...
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top