Functor Question - part II

B

BSand0764

Apologies for the length of this message, but I'm having problems
getting an alternate function to be executed via a functor
implementation.

I have two classes (BkgLand and BkgWater) that comprise a portion of a
much larger simulation. These classes exist in separate libraries
although the library that class BkgWater is in links in the library
containing the BkgLand class (sounds confusing I know). In the
simulation architecture that I'm using to implement these classes, the
Land based classes will be instantiated by default and the functors
will be registered for those classes. If the Water class objects are
present within the system I build (i.e. I've built an executable
containing the Water class), then the Water based classes will be
instantiated after the Land classes and those water functors are then
registered (and should take precedence).

When I test the simulation for a Land configuration I see that the
Land based functors execute just fine (and the Water objects aren't
present). When I configure the simulation for a 'Water case', I see
the message that the Land functors are being registered and then the
Water functors are being registered (as I expected), but when the
'Call_m' function is called (from the "Land" side of the simulation),
I get a segmentation fault. I checked for null pointers, but didn't
see evidence of that.

I don't know if :
- I've declared the funcTable arrays correctly and in the
appropriate sections of code (I had several compilation errors prior
to using the approach outlined below).
- There are some kind of scope issues
- Something between the two libraries is missing to allow the
land based side of the program to interpret the registered water
functions.

It almost seems as if the program doesn't know which function really
should be getting used (specFunc_0 from land or from water) when the
Call_m function is invoked for the water configuration.

Something to note, the programming guidelines I was given constrained
me to not compiling / linking libWater.so with the land based code,
only vice-versa is allowed.

Any suggestions would be greatly appreciated. Alf was already a big
help in an earlier question I posted on a related topic. Please see
the following code snippets. I will be glad to provide more
information if needed.

Danny


#ifndef TFUNCTOR_H
#define TFUNCTOR_H

#include "my_config.h"
#include "Struct1.h"
#include "Struct2.h"

BEGIN_MY_NAMESPACE

class TFunctor
{
public:

virtual void Call_m(STRUCT1*, STRUCT2*)=0;
};
END_MY_NAMESPACE

#endif //TFUNCTOR_H

#ifndef SPECFUNCTOR_H
#define SPECFUNCTOR_H

#include "my_config.h"
#include "TFunctor.h"

BEGIN_MY_NAMESPACE

template <class TClass> class TSpecificFunctor : public TFunctor
{
public:

// Constructor - takes pointer to an object and pointer to
// a member function and stores them in two private variables
TSpecificFunctor( TClass* _pt2Object, void(TClass::*tfpt)
(STRUCT1*, STRUCT2*) )
{ pt2Object = _pt2Object; fpt = tfpt; };

// override function "call" in base class
virtual void Call_m(STRUCT1* bkgnd, STRUCT2* geo)
{ (*pt2Object.*fpt) (bkgnd, geo);

private:
void (TClass::*fpt) (STRUCT1*, STRUCT2*);
};
END_MY_NAMESPACE

#endif //SPECFUNCTOR_H

#ifndef BKGLAND_H
#define BKGLAND_H

#include "my_config.h"

#include "Struct1.h"
#include "Struct2.h"

BEGIN_MY_NAMESPACE

class BkgLand
{
public:

// Constructor/Destructor
BkgLand() {};
virtual ~BkgLand() {};

void Initialize();
void Update();

TFunctor::TFunctor *funcTable[];
};

END_MY_NAMESPACE

#endif // BKGLAND_H


BKGLAND.cpp Code (compiled in library LIBGround.so):

#include "BkgLand.h"
#Include "SpecFunctor.h"
#include "LandScats.h"

void BkgLand::Initialize( )

cout << "REGISTER LAND FUNCTIONS" << endl;

// init_test function is a public member of the LandScats class
LandScats objLand;
TSpecificFunctor<LandScats> specFunc_0(&objLand,
&LandScats::init_test);
TFunctor::TFunctor *funcTable[] = { &specFunc_0 };
}

void BkgLand::Update()
{
//geom* and bkgndscat* are provided to this class via accessor
methods.

// Call appropriate registered function (can be land or water
based)
funcTable[0]->Call_m(bkgndscat, geom);
}

BKGWATER.cpp Code (compiled in a separate library, LIBWater.so, but
LIBGround is linked in when this library is built):

#include "BkgWater.h"
#include "TFunctor.h"
#include "SpecFunctor.h"
#include "WaterScats.h"

void BkgWater::Initialize()
{
cout << "REGISTER WATER FUNCTIONS" << endl;

// init_test function is a public member of the WaterScats
class
WaterScats objWater;
TSpecificFunctor<WaterScats> specFunc_0( &objWater,
&WaterScats::init_test);
TFunctor::TFunctor *funcTable[] = { &specFunc_0 };
}

#ifndef BKGWATER_H
#define BKGWATER_H

#include "Tfunctor.h"

BEGIN_MY_NAMESPACE
class BkgWater
{
BkgWater();
virtual ~BkgWater();

public:
virtual void Initialize();
TFunctor::TFunctor *funcTable[];

}
END_MY_NAMESPACE
#endif // BKGWATER_H
 
J

James Kanze

On Nov 11, 6:38 pm, (e-mail address removed) wrote:

[...]
There are several obvious errors in the code you posted. But
it's not the actual code, since it won't compile. (And you
really should strip out the namespace management macros junk
before posting. It may be necessary in your environment, but it
just causes confusion here.)
class TFunctor
{
public:
virtual void Call_m(STRUCT1*, STRUCT2*)=0;
};
template <class TClass> class TSpecificFunctor : public TFunctor
{
public:

// Constructor - takes pointer to an object and pointer to
// a member function and stores them in two private variables
TSpecificFunctor( TClass* _pt2Object, void(TClass::*tfpt)
(STRUCT1*, STRUCT2*) )
{ pt2Object = _pt2Object; fpt = tfpt; };

Where is pt2Object declared? What is its type (presumably
TClass*, but it could be a base class pointer, or even void*)?
// override function "call" in base class
virtual void Call_m(STRUCT1* bkgnd, STRUCT2* geo)
{ (*pt2Object.*fpt) (bkgnd, geo);

If pt2Object is a pointer, this statement isn't legal, and
shouldn't compile. If pt2Object is a TClass*, then what you
probably want is:

{ (pt2Object->*fpt)( bkgnd, geo ) ; }

Putting an additional parentheses around *pt2Object would also
work.
private:
void (TClass::*fpt) (STRUCT1*, STRUCT2*);
};
class BkgLand
{
public:

// Constructor/Destructor
BkgLand() {};
virtual ~BkgLand() {};

void Initialize();
void Update();
TFunctor::TFunctor *funcTable[];

Why TFunctor::TFunctor, instead of just TFunctor? I think it's
legal (because of type injection), but it is very confusing to
the reader, and I seem to recall encountering some compilers
which didn't accept it. (On seeing the name TFunctor after
TFunctor::, the compiler treated it as the "name" of a
constructor).

This won't compile anyway, of course, since you have to specify
the dimensions of a (non-static) member table.
void BkgLand::Initialize( )
cout << "REGISTER LAND FUNCTIONS" << endl;
// init_test function is a public member of the LandScats class
LandScats objLand;
TSpecificFunctor<LandScats> specFunc_0(&objLand,
&LandScats::init_test);
TFunctor::TFunctor *funcTable[] = { &specFunc_0 };

The above statement is a no-op. You define a local table of
pointers to TFunctor (again, same comment as above concerning
the name), with a dimension of 1, and initialize it with the
address of a local variable. You then immeately leave the
function, causing both the table and the local variable to
cease to exist. (Of course, the TSpecificFunctor instance
contains a pointer to still another local variable, and so
wouldn't be usable outside of the function anyway.
void BkgLand::Update()
{
//geom* and bkgndscat* are provided to this class via accessor
methods.
// Call appropriate registered function (can be land or water
based)
funcTable[0]->Call_m(bkgndscat, geom);

Here, of course, you use the funcTable variable of the object.
Since you've never initialized the contents of the table,
however, you've got totally undefined behavior.
BKGWATER.cpp Code (compiled in a separate library,
LIBWater.so, but LIBGround is linked in when this library is
built):

Has all of the problems of BKGLAND.cpp, so I won't bother
commenting.

Since your code won't compile, it's rather irrelevant to talk
about what it does on execution. If you want help with a
specific symptom, then you really should post the actual code
which causes that symptom. Otherwise, we really can't help you
much.
 
T

Tadeusz B. Kopec

On Nov 11, 6:38 pm, (e-mail address removed) wrote: [snip]
// override function "call" in base class virtual void
Call_m(STRUCT1* bkgnd, STRUCT2* geo) { (*pt2Object.*fpt) (bkgnd,
geo);

If pt2Object is a pointer, this statement isn't legal, and shouldn't
compile. If pt2Object is a TClass*, then what you probably want is:

{ (pt2Object->*fpt)( bkgnd, geo ) ; }

Putting an additional parentheses around *pt2Object would also work.

Surprisingly it should compile - .* and ->* operators have lower
precedence than dereference operator (*). But of course relying on this
makes no sense and operator ->* is appropriate here. I remember this
precedence only because it's so counter-intuitive.

[snip]
// Call appropriate registered function (can be land or water
based)
funcTable[0]->Call_m(bkgndscat, geom);

Here, of course, you use the funcTable variable of the object. Since
you've never initialized the contents of the table, however, you've got
totally undefined behavior.

I couldn't see its definition so I would expect linker error.
 
J

James Kanze

On Nov 11, 6:38 pm, (e-mail address removed) wrote: [snip]
// override function "call" in base class virtual void
Call_m(STRUCT1* bkgnd, STRUCT2* geo) { (*pt2Object.*fpt) (bkgnd,
geo);
If pt2Object is a pointer, this statement isn't legal, and shouldn't
compile. If pt2Object is a TClass*, then what you probably want is:
{ (pt2Object->*fpt)( bkgnd, geo ) ; }
Putting an additional parentheses around *pt2Object would also work.
Surprisingly it should compile - .* and ->* operators have lower
precedence than dereference operator (*). But of course relying on this
makes no sense and operator ->* is appropriate here. I remember this
precedence only because it's so counter-intuitive.

You're right.

I'll admit that I don't bother memorizing anything but the
"obvious" precedences: */ before +-, unary before binary, and
post-fix before pre-fix, and logical operators and comparisons
after everything else. Interestingly enough, this case is
actually covered by those rules: .* is a binary operator. But
I'm so used to the binding of . and -> that it didn't occur to
that .* and ->* would be different. (It's one of those things
that are obvious... once they've been pointed out to you.)
[snip]
// Call appropriate registered function (can be land or water
based)
funcTable[0]->Call_m(bkgndscat, geom);
Here, of course, you use the funcTable variable of the object. Since
you've never initialized the contents of the table, however, you've got
totally undefined behavior.
I couldn't see its definition so I would expect linker error.

It was defined as a non-static member of the class. The problem
is that he didn't give a dimension, so the definition wouldn't
be legal, and the compiler should have complained.

If it were a static member, of course, then the declaration in
the class is not a definition, so the type doesn't have to be
complete, and he can use a simple []. But then, as you say, he
needs a definition somewhere or the linker should complain.

The real problem, of course, is that he's not posting the real
code (at least judging from the symptoms he described).
 
T

Tadeusz B. Kopec

On Tue, 13 Nov 2007 09:45:13 +0000, James Kanze wrote:
[snip]
It was defined as a non-static member of the class. The problem is that
he didn't give a dimension, so the definition wouldn't be legal, and the
compiler should have complained.

It must this funny property of human brain - I saw what I thought it
should be not what it really was. I saw no dimension, I knew definition
needs a dimension so I saw 'static' there. :)
BTW: my gcc 4.1.3 needs -pedantic to complain about zero-sized arrays.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,185
Members
46,736
Latest member
AdolphBig6

Latest Threads

Top