Sign in to follow this  
Andrew Russell

Very Weird Error [CXX0070] (C++, templates, static members) [SOLVED]

Recommended Posts

OK, the story goes like this. I forgot to release one of my singletons and I'd finally had the last straw that my singleton class wasn't foolproof (it needed the programmer to dealocate it manually). I didn't want to remove the manual-dealocation thing, but I did want to have an error if the programmer screwed up. Thus I added this code:
template <class T>
class ASingleton
{
private:
    struct ReleaseCheck
    {
        ReleaseCheck() {}
        ~ReleaseCheck() {assert(!ASingleton<T>::ValidSingleton());}
    };
    static ReleaseCheck check;

    ... // rest of the class
};

template <class T> typename ASingleton<T>::ReleaseCheck ASingleton<T>::check;

Now, it didn't work and my breakpoints were comming up as question marks (ie: the destructor for ReleaseCheck wasn't being compiled). So I decide to run it and pull it up in the watch window. I got something very, very strange:
ASingleton<APackageManager>::check	CXX0070: Error: static member not present
ASingleton<APackageManager>::foo	CXX0017: Error: symbol "foo" not found	
ASingleton<APackageManager>::singleton	0x00d2abf8 {...}	APackageManager *
In other words - the memeber that has always worked, works. The member that isn't even there dosn't work, and does so in the way one would expect. The member that I want to work - completly dosn't work and I have no idea why. Now, a quick google reveals no results for CXX0070 or "static member not present". Searching MSDN with its own search engine revealed the same. So there is no handy documentation. So the question, obviously, is this: WTF? [Edited by - Andrew Russell on July 10, 2005 1:17:19 AM]

Share this post


Link to post
Share on other sites
Well - that's the point - it is legal, and it does compile (including with a full rebuild). It just dosn't want to actually do anything.

I'm using MSVC 7.1. My friend tried it in GCC and found that it also compiled, but it didn't run then either.

Share this post


Link to post
Share on other sites
I should add that practically identical code builds for me on GCC but never gets executed (like it never reaches the destructor). It's quite odd since the constructor for the struct also never happens O_o.

Share this post


Link to post
Share on other sites
template <class T> typename ASingleton<T>::ReleaseCheck ASingleton<T>::check;


Is the typename necessary? What happens if you exclude it from this line?

(Translation: I don't know what the heck the problem is. I'd like to throw something out there so that you might think a little bit harder.)

EDIT: Oh yeah, I know what it's for...just throwing something out there.

Share this post


Link to post
Share on other sites
Not exactly sure what's going on with the error codes, but I may know why your ReleaseCheck isn't destructing:

It might not be constructing in the first place.

GCC 3.4.2, MinGW, I take this source:

#include <iostream>
using namespace std;

template <class T>
class ASingleton
{
private:
struct ReleaseCheck
{
void foo() {}
ReleaseCheck() {}
~ReleaseCheck() {assert(!ASingleton<T>::ValidSingleton());}
};
static ReleaseCheck check;
public:
ASingleton() {
//check.foo();
}

static bool ValidSingleton() {
return true; //try and trigger release error
}
};

template <class T> typename ASingleton<T>::ReleaseCheck ASingleton<T>::check;

int main () {
ASingleton< int > int_singleton;
}



Compile and run:
C:\eclipse\workspace\test.13>Debug\test.13

C:\eclipse\workspace\test.13>_


Boring. Uncomment the check.foo() line, rebuild, and run:

C:\eclipse\workspace\test.13>Debug\test.13
Assertion failed: !ASingleton<T>::ValidSingleton(), file ../main.cc, line 12

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

C:\eclipse\workspace\test.13>_


HTH

Share this post


Link to post
Share on other sites
Quote:
Original post by Puzzler183
Yeah, it wasn't constructing. But why not?


Usually, statics are initialized upon (right before) first access. AFAIK this is even ANSI C++, although I can't say for certain as I don't have a copy.

If my memory serves, it's stated something along the lines of "a static will be initialized before first access". Since the ctor of one static could access another static, in ways possibly not determinable at compile time, the easiest solution to this otherwise potentially hard to meet requirement is to initialize the object right before construction.

Same applies to function statics, which I've abused to solidify order-of-construction for globals in the past (e.g. "foo bar;" -> "bar & foo( void ) { static bar b; return b; }")

So, if it's never accessed, it ends up never being constructed. And if it's never constructed, there's no need to destruct it, and trying to would probably blow something up, or something.

Share this post


Link to post
Share on other sites
Yep. Fixed it up nicely.

The class now looks like this:

template <class T>
class ASingleton
{
struct ReleaseCheck
{
ReleaseCheck() {}
~ReleaseCheck() { assert(!ASingleton<T>::ValidSingleton()); }
void Dummy() {}
};
static ReleaseCheck check;

ASingleton()
{
assert(!singleton);
singleton = static_cast<T*>(this);
check.Dummy();
}

...
};

template <class T> typename ASingleton<T>::ReleaseCheck ASingleton<T>::check;

Share this post


Link to post
Share on other sites
I've actually had this problem before in a slightly different way (the class "not" being compiled was seperate - not a member class), and I actually solved it in a similar way (a different kind of dummy function). It's a shame I didn't realise what caused it - I could have thought to transfer the solution.

Anyway - quick check of when things are initialised and such reveals the static members are initialised before WinMain. Another test reveals that the new code does indeed give an assert error if you forget to release the singleton (yay!).

Ratings for you, sir.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this