question about objects passed into constructors

F

fighter1

Hello,

I have a question about passing an object into a constructor.

How can I check to make sure that the object is good/valid that is
being passed into the constructor.

Obviously I could check to see if it is non-NULL, but that still will
not necessarily tell me anything.

For example:

/* here is a constructor car that takes an engine class as an
argument. But, I better check to make sure that engine is valid
so how do I do that?
*/
Car::Car( Engine* engine )
{

// check to make sure that engine is valid.


}


Thanks in advance for any help,
John
 
E

E. Robert Tisdale

I have a question about passing an object into a constructor.

How can I check to make sure that
the object that is being passed into the constructor is good/valid.

Obviously I could check to see if it is non-NULL
but that still will not necessarily tell me anything.


class Engine {
private:
// representation
const
unsigned int Valid;
public:
//functions
bool valid(void) const {
return 0x55555555 == Valid;
}
// constructors
Engine(void): Valid(0x55555555) { }
~Engine(void) { Valid = 0xAAAAAAAA; }
};
 
D

Donovan Rebbechi

How can I check to make sure that the object is good/valid that is
being passed into the constructor.

Obviously I could check to see if it is non-NULL, but that still will
not necessarily tell me anything.

For example:

/* here is a constructor car that takes an engine class as an
argument. But, I better check to make sure that engine is valid
so how do I do that?
*/

What do you mean by "valid" ? The Engine class should be responsible for making
sure that Engine objects are not "invalid".

Since you are passing in a pointer, you need to check for a null pointer.

If the pointer is not null, it's the callers responsibility to pass in a valid
pointer. There's no way to check whether a pointer is "wild" or not.

Cheers,
 
D

David White

Hello,

I have a question about passing an object into a constructor.

How can I check to make sure that the object is good/valid that is
being passed into the constructor.

Obviously I could check to see if it is non-NULL,

Unless it's a pointer there's nothing to check, NULL-wise.
but that still will
not necessarily tell me anything.

For example:

/* here is a constructor car that takes an engine class as an
argument. But, I better check to make sure that engine is valid
so how do I do that?
*/
Car::Car( Engine* engine )
{

// check to make sure that engine is valid.

You'll have to ask the Engine object, if it has a member that serves that
purposes. Other than checking whether the supposed memory the object
occupies is real memory, which is a system-specific matter and OT here,
there is no general way to tell if an object is valid. If the Engine itself
can't tell you it's valid, nothing else can.

DW
 
D

David White

E. Robert Tisdale said:
class Engine {
private:
// representation
const
unsigned int Valid;
public:
//functions
bool valid(void) const {
return 0x55555555 == Valid;
}
// constructors
Engine(void): Valid(0x55555555) { }
~Engine(void) { Valid = 0xAAAAAAAA; }
};

Of course, with the same "valid" value used in all instances, and perhaps in
other classes as well, it will greatly increase the probability that some
dangling or uninitialized pointer will be unlucky enough to point somewhere
such that the Valid member happens to be 0x55555555.

DW
 
P

Peter Koch Larsen

Hello,

I have a question about passing an object into a constructor.

How can I check to make sure that the object is good/valid that is
being passed into the constructor.

Obviously I could check to see if it is non-NULL, but that still will
not necessarily tell me anything.

For example:

/* here is a constructor car that takes an engine class as an
argument. But, I better check to make sure that engine is valid
so how do I do that?
*/
Car::Car( Engine* engine )
{

// check to make sure that engine is valid.


}


Thanks in advance for any help,
John


Most probably, you need to not use a pointer:

Car::Car(Engine const& engine)

as this will assure a proper engine-object to be passed always.

If "Car" does not need an engine, you could keep your present design.

If Car needs to use an engine, but you for some reason want to keep the
signature of the constructor (the reason for this would not be based in the
language), You should throw from the constructor:

Car::Car( Engine* engine)
{
if (!engine) throw 0; // have a proper exception here!!
// continue construction here
}

but be prepared to refactor later.

I can't really recommend Tisdales trick unless there is a compelling reason
to do it that way (e.g. if you are not allowed to throw an exception in the
constructor).

/Peter
 
C

Chris Theis

Hello,

I have a question about passing an object into a constructor.

How can I check to make sure that the object is good/valid that is
being passed into the constructor.

Obviously I could check to see if it is non-NULL, but that still will
not necessarily tell me anything.
[SNIP]

Well, the whole problem arises from the word "valid". It depends very much
what you define as a valid object. Testing for NULL is a way of checking
whether a pointer is valid but this doesn't tell you whether the object,
which this pointer points to, has a "valid = reasonable" state. If you just
want to check whether the pointer has something to point to then this NULL
test is fine. Otherwise you will have to define what characterizes a
"good/valid" object state and supply some function to check this. (See
Robert Tisdale's post).

Cheers
Chris
 
D

Dag Henriksson

Hello,

I have a question about passing an object into a constructor.

How can I check to make sure that the object is good/valid that is
being passed into the constructor.

Why would you like to do that?
IMHO the right way to do it is that in the documentation of the class say
something as:

Car::Car( Engine* engine )
Precondition: engine points to a valid Engine object.

and leave the responsibility for this to the caller. This is the approach
the standard library has.

For example:
18.6.2.3 set_unexpected
unexpected_handler set_unexpected(unexpected_handler f) throw();
1 Effects: Establishes the function designated by fas the current
unexpected_handler.
2 Requires: f shall not be a null pointer.
 
D

Daniel T.

Hello,

I have a question about passing an object into a constructor.

How can I check to make sure that the object is good/valid that is
being passed into the constructor.

Obviously I could check to see if it is non-NULL, but that still will
not necessarily tell me anything.

For example:

/* here is a constructor car that takes an engine class as an
argument. But, I better check to make sure that engine is valid
so how do I do that?
*/
Car::Car( Engine* engine )
{

// check to make sure that engine is valid.


}

In other words, you want to guard against someone doing something like:

Car myCar( (Engine*) 0x543562 );

(where 0x543562 doesn't point to an actual Engine object.) Or some such?

There isn't much you can do about this, but here is one idea:

class Engine {
static std::set< Engine* > allEngines;
public:
static bool isValid( Engine* anEngine ) {
return allEngines.count( anEngine ) == 1;
}

Engine() {
allEngines.insert( this );
}
~Engine() {
allEngines.erase( this );
}
};

Now:

Car::Car( Engine* engine ) {
assert( Engine::isValid( engine ) );
//...
}

This is not a cheep operation! It will probably slow your program down
tremondusly if you do this with every class. Be sure to make it so you
can define the extra code out when you build a release version.
 
D

Dag Henriksson

Daniel T. said:
In other words, you want to guard against someone doing something like:

Car myCar( (Engine*) 0x543562 );

(where 0x543562 doesn't point to an actual Engine object.) Or some such?

There isn't much you can do about this, but here is one idea:

Your idea will probably work on some implementation, but technically is the
effect of using an invalid pointer value undefined and could cause a
system-generated runtime fault.

That means that you can not check if a pointer argument is valid or not
inside a function (or anywhere else). When the pointer is passed to the
function (by value) we have already invoked undefined behavior.
 
J

jeffc

Peter Koch Larsen said:
If Car needs to use an engine, but you for some reason want to keep the
signature of the constructor (the reason for this would not be based in the
language), You should throw from the constructor:

Car::Car( Engine* engine)
{
if (!engine) throw 0; // have a proper exception here!!
// continue construction here
}

but be prepared to refactor later.

I can't really recommend Tisdales trick unless there is a compelling reason
to do it that way (e.g. if you are not allowed to throw an exception in the
constructor).

Yeah, but there is also the requirement that the pointer is "good/valid".
Depending on what the OP meant, your check doesn't guarantee that either.
 
E

E. Robert Tisdale

Chris said:
Well, the whole problem arises from the word "valid".
It depends very much what you define as a valid object.
Testing for NULL is a way of checking whether a pointer is valid
but this doesn't tell you whether the object to which
this pointer points has a "valid = reasonable" state.
If you just want to check
whether the pointer has something to point to,
then this NULL test is fine.
Otherwise, you will need to define
what characterizes a "good/valid" object state
and supply some function to check this.
(See Robert Tisdale's post).

A NULL pointer is valid pointer which always points to
an invalid object of any type.
There is, unfortunately, *no* way to determine whether
any other pointer (valid or not) references a valid object.
If every attempt to access an invalid object through a pointer
resulted in a segmentation fault, a bus error
or some other system error, there would be no problem.
The problem is that your program may access
and, perhaps, corrupt other valid data in your program.
It may also access an object that you have already deleted
but which has not been reallocated and reinitialized
so you must stamp it with a bit pattern which marks it invalid
when the program calls your constructor.
 
E

E. Robert Tisdale

Dag said:
Your idea will probably work on some implementation, but technically is the
effect of using an invalid pointer value undefined and could cause a
system-generated runtime fault.

That means that you can not check if a pointer argument is valid or not
inside a function (or anywhere else). When the pointer is passed to the
function (by value) we have already invoked undefined behavior.

I think that you missed the point.
A system-generated runtime fault can be trapped
and your program can recover or abort.
The problem occurs when no fault is generated
and your program initializes a Car object with an invalid Engine object.
 
P

puppet_sock

Dag Henriksson said:
Your idea will probably work on some implementation, but technically is the
effect of using an invalid pointer value undefined and could cause a
system-generated runtime fault.

That means that you can not check if a pointer argument is valid or not
inside a function (or anywhere else). When the pointer is passed to the
function (by value) we have already invoked undefined behavior.

Is it still undefined behaviour if I never dereference the pointer?
I agree it is certainly undefined if I try to access memory an
invalid pointer points at as though it were valid. But simply passing
an invalid pointer value through a function call is undefined?
Just checking...
Socks
 
R

Ron Natalie

Is it still undefined behaviour if I never dereference the pointer?
I agree it is certainly undefined if I try to access memory an
invalid pointer points at as though it were valid. But simply passing
an invalid pointer value through a function call is undefined?
Just checking...

Yes it is. It's possible (though I've never seen a machine where this
happens) where merely copying an out of range pointer might trap.
 
L

lilburne

David said:
Of course, with the same "valid" value used in all instances, and perhaps in
other classes as well, it will greatly increase the probability that some
dangling or uninitialized pointer will be unlucky enough to point somewhere
such that the Valid member happens to be 0x55555555.

You can be unlucky in many ways, but the scheme above in my
experience catches 99.99999% of bugs due to accessing
deleted objects. And they are usually caught the first time
the offending code is exercised. Personally I'd assert the
validity in every method too.
 
P

Peter Koch Larsen

jeffc said:
Yeah, but there is also the requirement that the pointer is "good/valid".
Depending on what the OP meant, your check doesn't guarantee that either.

Well... there is no way to check if a pointer is valid in C++. It better
always be.

/Peter
 
O

Old Wolf

How can I check to make sure that
class Engine {
private:
// representation
const
unsigned int Valid;
public:
//functions
bool valid(void) const {
return 0x55555555 == Valid;

Signed-unsigned comparison.
}
// constructors
Engine(void): Valid(0x55555555) { }
~Engine(void) { Valid = 0xAAAAAAAA; }
};

I thought this was a troll at first, but others seem to have replied
to it seriously. Any standards-conforming compiler could optimise
away valid() entirely:

If UB has not been invoked, then valid() must return true.
If UB has been invoked, the program can do anything (specifically,
make valid() return true).

NB. I am ignoring (as you have) the case 0x55555555 > UINT_MAX.
However I suspect in this case valid() would always be false,
hence it can be optimised away still.

NB2. In a newsgroup for Standard C++, I think this construct
is fairly off-topic.
 
L

lilburne

Old said:
I thought this was a troll at first, but others seem to have replied
to it seriously. Any standards-conforming compiler could optimise
away valid() entirely:

Only if someone has been silly enough to inline it. The example just
gives a flavour of how one might test the objects pulse. Mostly 'valid'
would be a class, with all its members defined outline, and an
assert_ok() method which asserts on failure.
 

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,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top