Solved

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

Posted on 2011-02-16
4
771 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 30

Expert Comment

by:Zoppo
Comment Utility
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
Comment Utility
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 30

Accepted Solution

by:
Zoppo earned 500 total points
Comment Utility
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
Comment Utility
Well, thanks, I'll think a little bit more about how to "workaround" this..
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Errors will happen. It is a fact of life for the programmer. How and when errors are detected have a great impact on quality and cost of a product. It is better to detect errors at compile time, when possible and practical. Errors that make their wa…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
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.
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.

772 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

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now