Changing member variables outside contstructor Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
zobbo
Experienced Solver
Experienced Solver
Posts: 58
Joined: Sat Aug 18, 2007 4:41 am

Changing member variables outside contstructor

Post by zobbo »

Hello,

I have an issue with my code, in that I can set member variables, but only in the constructor. I can compile my code, however, it causes an access violation when I try to set a member variable set in the header file. I can get around this by declaring a variable within the cpp file, but that kind of ruins the point of using classes. The class I have problems with is derived from my base class, which is derived from wxAppConsole.

My derived class header:



Code: Select all

#pragma once

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
//#include <iostream>

#ifdef __BORLANDC__
#  pragma hdrstop
#endif

// for all others, include the necessary headers
#ifndef WX_PRECOMP
#  include "wx/wx.h"
#endif

#include <wx/socket.h>


#include "TestApplication.h"

class Server : public TestApplication
{

	friend class ProxyTestSuite; // for test rig




public:
	Server(void);
	~Server(void);

	void OnServerEvent(wxSocketEvent& event);
	void SetServerEvent(int setting);

private:
	wxSocketServer* socServer_;
	int serverEventResult_; //for test rig
	

	DECLARE_EVENT_TABLE()


};

And cpp:

Code: Select all

#include "Server.h"
#include "wx/cmdline.h"
#include <iostream>


enum
{
  // id for sockets
  SERVER_ID = 100,
  SOCKET_ID
};

BEGIN_EVENT_TABLE(Server, TestApplication)
		EVT_SOCKET(SERVER_ID, Server::OnServerEvent)
END_EVENT_TABLE()


Server::Server(void)
{
	// Create the address - defaults to localhost:0 initially
  wxIPV4address addr;
  addr.Service(3000);

  // Create the server socket
  socServer_ = new wxSocketServer(addr);

   // Setup the event handler and subscribe to connection events
  socServer_->SetEventHandler(*this, SERVER_ID);
  socServer_->SetNotify(wxSOCKET_CONNECTION_FLAG);
  socServer_->Notify(true);

  serverEventResult_ =0; //this works
 
}

Server::~Server(void)
{
}

void Server::OnServerEvent(wxSocketEvent& event)
{

	switch(event.GetSocketEvent())
  {
	case wxSOCKET_CONNECTION : /*serverEventResult_=1;*/ std::cout << "\nServer: wxSOCKET_CONNECTION\n"; break;
	default                  : /*serverEventResult_=0;*/ std::cout << "\nServer: Unexpected event!\n"; break;
  }

	SetServerEvent(1); //access violation
}

void Server::SetServerEvent(int setting)
{
	
	serverEventResult_ = setting; //access violation


}
As you can see, setting the serverEventResult int works in the constructor, but not in the accessor method. I have tried various other member variables and get the same result.

Should I be getting the application instance or something because as far as I can see setting the member variable in that way is normal. Normally it would be set in the switch statement in OnServerEvent, but I'm trying to just set it for now, without much luck.

Regards,
Zobbo
Zobbo

Wxwidgets 2.9.0, Visual C++ Express 2005, Windows Vista x64 Home Premium
Auria
Site Admin
Site Admin
Posts: 6695
Joined: Thu Sep 28, 2006 12:23 am
Contact:

Post by Auria »

I'm not sure what's wrong - all I can say, is tjhat, usually, the second argument of BEGIN_EVENT_TABLE is a wx class (a wxEventHandler derivate) Not knowing what TestApplication is makes things harder

Also, maybe show how to class is created/deleted/managed. Maybe your class is unexpectedly destroyed and wx doesn't know about it or something like that
mc2r
wxWorld Domination!
wxWorld Domination!
Posts: 1195
Joined: Thu Feb 22, 2007 4:47 pm
Location: Denver, Co
Contact:

Re: Changing member variables outside contstructor

Post by mc2r »

zobbo wrote:I can compile my code, however, it causes an access violation when I try to set a member variable set in the header file.
You don't show this, so it is hard to say whats wrong.
zobbo wrote:I can get around this by declaring a variable within the cpp file, but that kind of ruins the point of using classes.
I'm not sure what you are talking about here. Are you creating a variable or member variable. Also, it seems you are confused about header files and cpp files (excuse me if I am wrong). The header file should declare any variables, classes, types, etc... which will be accessed by clients of the cpp code. ie... anything using your class. But these all need to be defined in the cpp file.

This will let you initialize a member variable outside of your constructor(in the cpp file) but I believe it needs to be static.

Code: Select all

Server::serverEventResult_ = 0;
zobbo wrote:

Code: Select all

void Server::SetServerEvent(int setting)
{
	
	serverEventResult_ = setting; //access violation


}
This usually happens when you the accessor is called from an invalid/uninitialized pointer to the base class, as Auria has pointed out.

also, per auria creation/deletion/managment code showing how the class is used would help.

-Max
zobbo
Experienced Solver
Experienced Solver
Posts: 58
Joined: Sat Aug 18, 2007 4:41 am

Post by zobbo »

Hi,

Thanks for your responses. It was a bit silly not showing my TestApplication code, so here it is:

TestApplication.h:

Code: Select all

#pragma once

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
//#include <iostream>

#ifdef __BORLANDC__
#  pragma hdrstop
#endif

// for all others, include the necessary headers
#ifndef WX_PRECOMP
#  include "wx/wx.h"
#endif




//#ifndef TESTAPPLICATION_H
//#define TESTAPPLICATION_H

class Server; //forward declaration so we can use instance before calling server.h

class TestApplication : public wxAppConsole
{

friend class ProxyTestSuite;

public:
	TestApplication(void);
	~TestApplication(void);
	
	
    virtual bool OnInit();
    virtual int  OnRun();
    virtual int  OnExit();

protected:
	Server* server_;

	
};
And the implementation:

Code: Select all

#include "TestApplication.h"
#include "Server.h"

#ifndef CXXTEST_RUNNING
#define CXXTEST_RUNNING
#endif

#define _CXXTEST_HAVE_EH
#define _CXXTEST_ABORT_TEST_ON_FAIL
#include <cxxtest/TestListener.h>
#include <cxxtest/TestTracker.h>
#include <cxxtest/TestRunner.h>
#include <cxxtest/RealDescriptions.h>
#include <cxxtest/ParenPrinter.h>

IMPLEMENT_APP_CONSOLE(TestApplication);


TestApplication::TestApplication(void)
{
}



TestApplication::~TestApplication(void)
{
}



bool TestApplication::OnInit()
{
    
	CxxTest::ParenPrinter().run();
	
return true;

}



int TestApplication::OnRun()
{
	
	return 0;
}



int TestApplication::OnExit()
{

    return 0;
}


/////Test rig code///////////////////////////////////////////////////////////////////////////////////////////////

//int main() {
 //return CxxTest::ParenPrinter().run();
//}
#include "C:\Users\Ian\InfluxProxyWorkingCopy\msvc\ProxyTestSuite.h"

static ProxyTestSuite suite_ProxyTestSuite;

static CxxTest::List Tests_ProxyTestSuite = { 0, 0 };
CxxTest::StaticSuiteDescription suiteDescription_ProxyTestSuite( "C:\\Users\\Ian\\InfluxProxyWorkingCopy\\msvc\\ProxyTestSuite.h", 10, "ProxyTestSuite", suite_ProxyTestSuite, Tests_ProxyTestSuite );

static class TestDescription_ProxyTestSuite_testServer : public CxxTest::RealTestDescription {
public:
 TestDescription_ProxyTestSuite_testServer() : CxxTest::RealTestDescription( Tests_ProxyTestSuite, suiteDescription_ProxyTestSuite, 18, "testServer" ) {}
 void runTest() { suite_ProxyTestSuite.testServer(); }
} testDescription_ProxyTestSuite_testServer;

#include <cxxtest/Root.cpp>

The stuff at the bottom is CxxTest code which I use, the actual tests are in the ProxyTestSuite.h header:

Code: Select all

#pragma once

#include "TestApplication.h"
#include <wx/socket.h>





class ProxyTestSuite : public CxxTest::TestSuite
{



public:


		void testServer( void )
		{

			TestApplication* app = new TestApplication();
			//Server* srv = new Server();

			 wxSocketEvent* ev1;

			 ev1 = new wxSocketEvent(2);//wxconnection event
			 ev1->m_event=wxSOCKET_CONNECTION; //MUST DO THIS!			
			 
			 wxSocketEvent* ev2 = new wxSocketEvent(999);//invalid event
			

			 app->server_->OnServerEvent(*ev1);//wxsocketconnection
//			 TS_ASSERT_EQUALS(serverEventResult,1);

			 app->server_->OnServerEvent(*ev2);//unexpected event
			 app->server_->SetServerEvent(1);
			 //app->server_->socServer_ = NULL;
			// TS_ASSERT_EQUALS(serverEventResult,0);
			 
			
			//TS_WARN("TODO: Add documentation for DoxyGen");
		}

		

};
As for the member variable stuff, yes I want to use member variables, rather than non-member variables, I wondered if I had to make them static to work, but then I thought that if I created another instance it wouldn't be instance specific since it was static, if that makes sense. Hopefully the CxxTest stuff won't make things too tricky to decipher, as I use it as a black box pretty much.

So, in ProxyTestSuite you can see I'm trying to set the member variable server result, this is just a test, obviously normally the Server function itself would set this and then my assertions would pass, but I am just trying to set the member first without the access violation.

Thanks for the help.

Regards,
Zobbo
Zobbo

Wxwidgets 2.9.0, Visual C++ Express 2005, Windows Vista x64 Home Premium
Auria
Site Admin
Site Admin
Posts: 6695
Joined: Thu Sep 28, 2006 12:23 am
Contact:

Post by Auria »

I *think* you can't use events with console app ( I don't know that stuff very much, so pelase don't beleive everything I say and do your own research ;) ) What if you make it a non-console app?
zobbo
Experienced Solver
Experienced Solver
Posts: 58
Joined: Sat Aug 18, 2007 4:41 am

Post by zobbo »

The events work fine, it's just changing the member variables that are the problem. The events fire etc..

I have tried using a WxApp derived class before it was over complicating things with my test rig so I changed it to a console based app, but I never got as far as changing the member variables in the same way in the wxApp code.

I may be wrong, but I thought all of wx was events based, so that would make the console app pointless if it was the case?

Regards,
Zobbo
Zobbo

Wxwidgets 2.9.0, Visual C++ Express 2005, Windows Vista x64 Home Premium
DavidHart
Site Admin
Site Admin
Posts: 4254
Joined: Thu Jan 12, 2006 6:23 pm
Location: IoW, UK

Post by DavidHart »

Hi Zobbo,

I don't know why you have this problem, but a suggestion as to where to look. With your debugger (or using wxLogDebug or equivalent) find the value of 'this' in the constructor, and then inside Server::OnServerEvent. I suspect that you'll find they are different, which would explain your access violations.

Why would this happen? Normally because of using wxEvtHandler::Connect with the wrong eventSink parameter. You aren't explicitly doing this, but I wonder if that is happening somewhere in the socket code.

I know nothing about sockets so, if my guess is correct, someone else will have to tell you why.

Regards,

David
Auria
Site Admin
Site Admin
Posts: 6695
Joined: Thu Sep 28, 2006 12:23 am
Contact:

Post by Auria »

zobbo wrote:The events work fine, it's just changing the member variables that are the problem. The events fire etc..
well, not supported does not mean they will not run at all, it might mean it will run but give unpredictable results (anyway I'm not really sure about this, but might be worth investigating)
zobbo
Experienced Solver
Experienced Solver
Posts: 58
Joined: Sat Aug 18, 2007 4:41 am

Post by zobbo »

The problem was actually pretty simple (i.e. me beig simple), I hadn't actually created an instance of Server at any point, so it was obviously a null pointer. I realised when following David's advice and using a breakpoint in the Server ctor, obviously the breakpoint was never reached. I'll know what to look for next time I see access violation though.

But I ran straight into another problem, if I put the server creation in the TestApplication ctor,

Code: Select all

TestApplication::TestApplication(void)
{
	server_ = new Server(); //stack overflow
}
it gives me a stack overfow in string.cpp when trying to de-allocate a string, but I never use a wxString...:evil:

Code: Select all

void wxStringData::Free()
{
    free(this);
}

Creating a server directly doesn't cause this problem. I grew the stack, same issue, I suppose I could alter EXTRA_ALLOC but I don't see why it's even happening in the first place.

Regards,
Zobbo[/code]
Zobbo

Wxwidgets 2.9.0, Visual C++ Express 2005, Windows Vista x64 Home Premium
Post Reply