I am currently in the middle of a code cleanup of my solution, which consists of a static library and two applications that depend on it. As a part of this code cleanup, I've been converting all of my loops over std::vectors to use iterators rather than indices. Everything was going well, until I converted a function (in the library) that is called during the construction of a global object (in an application). The function in question populates a std::vector, and then searches the vector for an object that matches the description passed to the function, returning the first match. If no match is found, the front of the vector is returned.
I've managed to reduce the issue to the following code:
Library - Bar.h
struct Bar
{
int val;
Bar(int val = 0);
static Bar const& ByVal(int val);
};
Library - Bar.cpp
#include "Bar.h"
#include <vector>
using namespace std;
namespace { vector<Bar> bars; } // It is irrelevant whether bars is in an
// anonymous namespace or not; the results are
// the same.
Bar::Bar(int _val) : val(_val) { }
Bar const& Bar::ByVal(int val)
{
if (bars.empty())
{
bars.push_back(Bar(1));
bars.push_back(Bar(2));
}
#if 1
for (vector<Bar>::const_iterator it = bars.begin();
it != bars.end();
++it) // The assertion fails here. However, when the for loop is
// replaced with a while loop, it's the it != bars.end() part
// that fails.
{
if (it->val == val)
return *it;
}
return bars.front();
#else
for (size_t i = 0;
i < bars.size();
++i)
{
if (bars[i].val == val)
return bars[i];
}
return bars[0];
#endif
}
Application - Foo.cpp
#include <Bar.h>
#include <iostream>
using namespace std;
struct Foo
{
Foo()
{
Bar bar = Bar::ByVal(0);
cout << bar.val << endl;
}
};
Foo foo;
int main(int argc, char** argv)
{
return 0;
}
If the preprocessor conditional in Bar.cpp is changed to 0, the code executes flawlessly. Otherwise, the following assertion is shown:
Debug Assertion Failed!
Program: C:\Work\Reduction\Debug\Foo.exe
File: c:\program files (x86)\microsoft visual studio 10.0\vc\include\vector
Line: 238
Expression: vector iterators not compatible
This is under a brand new solution with brand new projects in Visual Studio 2010. The only settings that were changed on the projects were the ones necessary to get the application to link to the static library.
In an attempt to figure out what's causing the crash, I've discovered that the code works under the following conditions:
- When compiled in Release mode.
- When the library's bars vector is declared as extern, and is defined in the application itself.
- When the application's foo variable is moved inside of the main() function.
- When the code from the library is moved entirely to the application.
- When compiled under Visual Studio 2008.
Any help would be greatly appreciated, even if it means going back to using indices or VS2008. I've been searching frantically and banging my he开发者_Python百科ad on this issue for nearly two days now.
The C++ standard does not guarentee that bars
's constructor will be called before that of foo
. This is sometimes called the 'static initialization order fiasco'; you may get lucky in eg VS2008, but that doesn't mean the problem goes away. The page linked suggests a few potential solutions to this problem, one of which is to use a function-level static to ensure it's initialized prior to use.
精彩评论