?
Solved

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

Posted on 2011-02-16
4
Medium Priority
?
785 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 2000 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

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

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

When writing generic code, using template meta-programming techniques, it is sometimes useful to know if a type is convertible to another type. A good example of when this might be is if you are writing diagnostic instrumentation for code to generat…
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 viewer will learn how to clear a vector as well as how to detect empty vectors in C++.
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.
Suggested Courses

801 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