Solved

Problem initializing (extern) array, C++, MFC

Posted on 2011-02-16
4
782 Views
Last Modified: 2012-05-11
Hi.
I have a problem initializing array..
Program compiles without any errors & warnings, but when it starts ASSERT failure occurs,
because array elements are <bad pointers>.
See some code snippets..
Any help would be highly appreciated!!
In one header, lets call it A.h is defined struct TranslationPair and this header is included in stdafx.h:
struct TranslationPair
{
	TranslationPair(LPCTSTR sk, LPCTSTR sv) : sKey(sk), sDefVal(sv)
	{ }

	TranslationPair(TranslationPair& tp) : sKey(tp.sKey), sDefVal(tp.sDefVal)
	{ }

	

	CString sKey;
	CString sDefVal;
};

Then in stdafx.cpp is defined (and initialized) array arUserPermissionsDescs:
const TranslationPair arUserLevels[SECURITY_MAX_PERMISSIONS] = 
{
	TranslationPair ( _T("A"), _T("A") ),
              TranslationPair ( _T("B"), _T("B") ),
};
Now in another file, lets call it B.h:
extern const TranslationPair arUserLevels[SECURITY_LEVELS_NR];
ASSERT occurs in one of the methods of class defined in B.h & B.cpp:
void B::func()
{
  CString s = _T("AA");
  s == arUserLevels[0].sKey; // ASSERT, aruserLevels[0] - bad pointer, probably, array not initialized.
}
Some info about application:
1) It's MFC application.
2) Call stack looks like:  __tmainCRTStartup()->....->constructor of CMyApp(which is derived from CWinApp)->constructor of class defined in B(i.e it's called from constructor of CMyApp) -> B::func()
3) That's all, any ideas

Open in new window

0
Comment
Question by:SpringMVC
  • 2
  • 2
4 Comments
 
LVL 31

Expert Comment

by:Zoppo
ID: 34908224
Hi SpringMVC,

I guess the problem is caused by the fact you try to access the array within your CWinApp-derived classes constructor (i.o.w. when 'theApp' is initialized).

In this case it's not granted that 'arUserLevels' is already initialized since both 'arUserLevels' and 'theApp' are global variables, so it's undefined which one is initialized first.

I think to get this working you should move the code which accesses 'arUserLevels' (so the code from the app's constructor which calls 'B::func') to anywhere else where you know everything global is initialized completeley, i.e. to your CWinApp-derived classes 'InitInstance' method.

Hope that helps,

ZOPPO
0
 

Author Comment

by:SpringMVC
ID: 34908518
Thanks for suggestion, probably, you are right.

But in past it was:
TCHAR *arUserLevels[MAX] =
{
  _T("Admin", _T("User"), _T("SuperUser")
};
and it worked!!
Now problem is, that class B has no default contructor, and the object of B is in CMyApp..
So if I put initializing of B in InitInstance, I will have to make a default constructor for B, which will break application's logic/structure/or whatever it is..
Any ideas, how can I make refactoring? :)

P.S By the way, sorry for English :)
0
 
LVL 31

Accepted Solution

by:
Zoppo earned 500 total points
ID: 34908652
IMO the shown code worked earlier but doesn't work anymore is that you exchanged const string literals with structs. With the new code the structs within 'arUserLevels' have to be initialized during startup in order to call every entry's constructor. With the 'old' code this wasn't needed since 'arUserLevels' contained simply const char pointers.

I think there may be several ways to workaround this. One which maybe suitable could be to move the array to a static member function. For example if CMyApp is the CWinApp-derived class this could look like this:

// myapp.h

#define SECURITY_MAX_PERMISSIONS 2

class CMyApp : publid CWinApp
{
 public:
  static const TranslationPair[SECURITY_MAX_PERMISSIONS]& GetUserLevels();
 ...
};

// myapp.cpp
...
const TranslationPair[SECURITY_MAX_PERMISSIONS]& CMyApp::GetUserLevels()
{
 static const TranslationPair arUserLevels[SECURITY_MAX_PERMISSIONS] =
 {
   TranslationPair ( _T("A"), _T("A") ),
   TranslationPair ( _T("B"), _T("B") ),
 };

 return arUserLevels;
}
...



Then , wherever you need it (so wherever you formerly accessed 'arUserLevels' directly) you can access it via that static function, i.e.:

void B::func()
{
  CString s = CMyApp::GetUserLevels()[0].sKey;
}


Hope that helps,

ZOPPO



PS: The code I posted isn't tested, I just wrote it from my mind, maybe it has bugs - unfortunateley I have to leave office now, so I cannot give more help before tomorrow morning CET - sorry ...
0
 

Author Comment

by:SpringMVC
ID: 34914005
Well, thanks, I'll think a little bit more about how to "workaround" this..
0

Featured Post

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Templates For Beginners Or How To Encourage The Compiler To Work For You Introduction This tutorial is targeted at the reader who is, perhaps, familiar with the basics of C++ but would prefer a little slower introduction to the more ad…
Introduction This article is the first in a series of articles about the C/C++ Visual Studio Express debugger.  It provides a quick start guide in using the debugger. Part 2 focuses on additional topics in breakpoints.  Lastly, Part 3 focuses on th…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.

820 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question