Solved

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

Posted on 2011-02-16
4
784 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

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…
C++ Properties One feature missing from standard C++ that you will find in many other Object Oriented Programming languages is something called a Property (http://www.experts-exchange.com/Programming/Languages/CPP/A_3912-Object-Properties-in-C.ht…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.

707 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