Is default behavior still desired in this case?

C

coal

Previously I've suggested permitting some modification to the
default behaviour wrt to exceptions thrown in a constructor.

http://preview.tinyurl.com/278u77

My guess is the default behaviour was decided when networking
was less prevalent and should be reconsidered now.

I'm not sure if the syntax/mechanism I suggested is good.

If you have

class Base { ...};
class Inter : public Base { ...};
class Derived : public Inter { ... };

and

Base* b = new (preserve) Derived(...);

and an exception comes from Derived's constructor, b would be
set to the Inter object since that much was built successfully.

I'm not sure if/how the syntax would fit in with placement new.

The rationale for preserving a base object is because the sender,
network and receiver have invested quite a bit in getting to the
point of having an Inter. Throwing everything away doesn't make
sense to me.

Brian Wood
Ebenezer Enterprises
www.webebenezer.net
 
J

johanatan

Previously I've suggested permitting some modification to the
default behaviour wrt to exceptions thrown in a constructor.

http://preview.tinyurl.com/278u77

My guess is the default behaviour was decided when networking
was less prevalent and should be reconsidered now.

I'm not sure if the syntax/mechanism I suggested is good.

If you have

class Base { ...};
class Inter : public Base { ...};
class Derived : public Inter { ... };

and

Base* b = new (preserve) Derived(...);

and an exception comes from Derived's constructor, b would be
set to the Inter object since that much was built successfully.

I'm not sure if/how the syntax would fit in with placement new.

The rationale for preserving a base object is because the sender,
network and receiver have invested quite a bit in getting to the
point of having an Inter. Throwing everything away doesn't make
sense to me.

Brian Wood
Ebenezer Enterpriseswww.webebenezer.net

But, what happens to the actual exception? Do the semantics of
'preserve' imply that the exception is eaten and unavailable to the
calling code? That would not seem to be very informative as you would
most surely still want to have the option of fixing the problem if
possible and trying again only the part that failed.
 
E

Erik Wikström

Previously I've suggested permitting some modification to the
default behaviour wrt to exceptions thrown in a constructor.

http://preview.tinyurl.com/278u77

My guess is the default behaviour was decided when networking
was less prevalent and should be reconsidered now.

I'm not sure if the syntax/mechanism I suggested is good.

If you have

class Base { ...};
class Inter : public Base { ...};
class Derived : public Inter { ... };

and

Base* b = new (preserve) Derived(...);

What is wrong with doing it manually, adding new keywords and changing
syntax just to make some rare cases does not seem like a very good idea
to me.

Base* b;
try {
b = new Derived(...);
}
catch(SomeException& e)
{
b = new Inter(...);
}
 
C

coal

But, what happens to the actual exception?  Do the semantics of
'preserve' imply that the exception is eaten and unavailable to the
calling code?  

I think it would be propagated as usual. The caller could
determine if the pointer was to anything useful.
That would not seem to be very informative as you would
most surely still want to have the option of fixing the problem if
possible and trying again only the part that failed.

The assumption I'm making is it isn't desirable to have to have
large buffers to support retries. One of the things discussed
in the thread I mentioned was a maximum message length. The
buffers might have to be as big as the max msg length if you
don't have something like preserve. I don't think that is the
size you would choose for the buffers if they didn't need to be
available for retries.

Brian Wood
Ebenezer Enterprises
 
C

coal

What is wrong with doing it manually, adding new keywords and changing
syntax just to make some rare cases does not seem like a very good idea
to me.

Base* b;
try {
  b = new Derived(...);}

catch(SomeException& e)
{
  b = new Inter(...);

}

I think it forces you to use inefficient buffer sizes. What you wrote
above would work if you have everything needed in a buffer, but it's
not as efficient as using something like preserve since the subobjects
would be destroyed and then rebuilt. Also, it isn't as flexible; if
the hierarchy were

Base
Inter1 : Base
Inter2 : Inter1
Derived : Inter2

you'd have to beef up the above code. What we want is for the
system to give the closest object it can to what was requested.

You don't know when you write code like the above if things will
sometimes mess up in Inter2's construction. In order to get to
an Inter1 you would wind up destroying an Inter1 twice and building
it three times. (That is assuming the same problem persists
between the attempt to build a Derived and an Inter2.)

Brian Wood
Ebenezer Enterprises
 
J

johanatan

I think it would be propagated as usual. The caller could
determine if the pointer was to anything useful.


The assumption I'm making is it isn't desirable to have to have
large buffers to support retries. One of the things discussed
in the thread I mentioned was a maximum message length. The
buffers might have to be as big as the max msg length if you
don't have something like preserve. I don't think that is the
size you would choose for the buffers if they didn't need to be
available for retries.

I don't know enough about what your classes are actually doing (or the
inspiration for this thread), but if you are talking about something
as specific as buffer sizes as the rationale for a grammar change,
then surely there is another way to design this sub-system even within
the confines of the current grammar. What about re-ordering the data
stream? Let objects be serialized with their most-derived instance
data specified first (and thus you would know that all of its
ancestors should be able to be constructed). (You could prepend
lengths as another idea or in combination with the first).

If I'm way off base here, can you give a little more bkg on what
exactly these proposed classes are doing? -or- if not, I'd just
suggest to 'think outside the box' :) --there's surely a way to do it
without a new 'preserve' mechanism.

(Another idea just occurred to me (but less elegant)-- turn your 'is-
a' relationships into 'has-a' relationships and let the objs construct
each other when needed, if you can't re-order the stream)-- yes, this
one's a hack, but it is at least possible.

--Jonathan
 
C

coal

I don't know enough about what your classes are actually doing (or the
inspiration for this thread), but if you are talking about something
as specific as buffer sizes as the rationale for a grammar change,
then surely there is another way to design this sub-system even within
the confines of the current grammar.

I don't have a specific problem here. I agree buffer sizes
are specific, but I don't know of a better way than what I
suggested. What Erik wrote is an alternative, but I think
it has some weaknesses. If the maximum message size were
20 megabytes I think the buffers would have to be that big
in order to guarantee support for what he suggested.
Buffer sizes aren't the only thing; you also wind up
destroying and rebuilding multiple times.

I'm not suggesting that the syntax I proposed is how it
should be. There may be better ways to handle it.
What about re-ordering the data
stream? Let objects be serialized with their most-derived instance
data specified first (and thus you would know that all of its
ancestors should be able to be constructed).

Do you mean default constructed?
I guess you're saying something like

Derived dv; // default construction
serialize into dv

A problem with the serialization could still occur.
If that happens you're left with a Derived instance
in a probably inconsistent state. I would like to
have a valid subojbect if I can't get a valid Derived
object.

Also from that previous thread I mentioned, I'm thinking
about there being a stream/serialization constructor...

class Derived {
public:
Derived(handle stream) {}

};

Using that is more efficient than default constructing
and then serializing. I don't know if anyone is doing
that yet.

Brian Wood
Ebenezer Enterprises
 
J

johanatan

I don't have a specific problem here.  I agree buffer sizes
are specific, but I don't know of a better way than what I
suggested.  What Erik wrote is an alternative, but I think
it has some weaknesses. If the maximum message size were
20 megabytes I think the buffers would have to be that big
in order to guarantee support for what he suggested.
Buffer sizes aren't the only thing; you also wind up
destroying and rebuilding multiple times.

I'm not suggesting that the syntax I proposed is how it
should be.  There may be better ways to handle it.


Do you mean default constructed?
I guess you're saying something like

   Derived dv;         // default construction
   serialize into dv

Well, not necessarily. You could 'peek' into the stream and see
prepended useful information so that you could do (in pseudocode):

while (stream >> type)
{
obj o;
switch (type)
{
case derived:
o = Derived( stream );
break;
case base:
o = Base( stream );
break;
case ...:
...
...
}
}

In general, always prepend block sizes (if the buffer size is a
concern) or the obj type before the actual guts of the obj.
A problem with the serialization could still occur.
If that happens you're left with a Derived instance
in a probably inconsistent state. I would like to
have a valid subojbect if I can't get a valid Derived
object.

Why would a problem occur? Aren't you using TCP/IP? You should be
able with modern protocols to be assured at the application level that
you receive what was sent. If that isn't true, then you could always
invest in a better network stack of some sort (even if it means hand-
rolled middleware) to ensure that at the application level this is
true.
Also from that previous thread I mentioned, I'm thinking
about there being a stream/serialization constructor...

class Derived {
public:
  Derived(handle stream) {}

};

Using that is more efficient than default constructing
and then serializing.  I don't know if anyone is doing
that yet.

See above for example that doesn't use default constructing. Though,
the perf difference between default constructing and specialized
constructing would be minimal (but if it really matters, I guess it
really matters).

--Jonathan
 
C

coal

Well, not necessarily.  You could 'peek' into the stream and see
prepended useful information so that you could do (in pseudocode):

while (stream >> type)
{
  obj o;
  switch (type)
  {
     case derived:
        o = Derived( stream );
        break;
     case base:
        o = Base( stream );
        break;
     case ...:
        ...
     ...
  }

}

We already do something very similar -
http://preview.tinyurl.com/yro2ep
In general, always prepend block sizes (if the buffer size is a
concern)

I'm working on that. The thread I mentioned in the OP
convinced me it was necessary.
or the obj type before the actual guts of the obj.


The above is interesting but I don't see how it addresses
what I want to do. Given the above pseudo code, how do
you retrieve the Inter instance if the line
o = Derived( stream );

throws an exception in Derived's constructor?
Why would a problem occur?  

One problem would be failure to get needed memory
when data is being received/unmarshalled in an object.

Aren't you using TCP/IP?

Yes.
 You should be
able with modern protocols to be assured at the application level that
you receive what was sent.  If that isn't true, then you could always
invest in a better network stack of some sort (even if it means hand-
rolled middleware) to ensure that at the application level this is
true.



See above for example that doesn't usedefaultconstructing.  Though,
the perf difference betweendefaultconstructing and specialized
constructing would be minimal (but if it really matters, I guess it
really matters).

I did a few tests and they didn't make me very confident
about my point. Perhaps you're right.

Brian Wood
Ebenezer Enterprises
 
J

johanatan

We already do something very similar -http://preview.tinyurl.com/yro2ep


I'm working on that.  The thread I mentioned in the OP
convinced me it was necessary.


The above is interesting but I don't see how it addresses
what I want to do.  Given the above pseudo code, how do
you retrieve the Inter instance if the line
    o = Derived( stream );

throws an exception in Derived's constructor?

Well, my point was that, if you prepend the type and/or buffer sizes,
and you're using a sufficiently advanced communication medium (TCP/IP)
that guarantees that what was sent is what is actually received, then
you can on the sending end make sure to send a well-formed object that
will allow successful construction (on the receiving end).

If you're concerned about attacks, then you ought to have some other
level of end-to-end encryption or authentication mechanism in place to
prevent that (abstracted away from the problem of actually
constructing objects).
One problem would be failure to get needed memory
when data is being received/unmarshalled in an object.

Failure on the receiving end to allocate enough memory for the entire
object? If that's happens I'd just say the entire object would be
invalid. At the point you determine the type, you can do:

sizeof(type)

to see how much will be needed (that should include all base classes
in the calculation) and if there isn't enough, then the object would
not be constructed at all.

If you're getting that low on memory, needing and using a partially
constructed object would be the least of your worries, I would think.
What about thrashing and so forth? Your entire machine is probably
gonna be useless at the point you fill up VM.

--Jonathan
 
J

johanatan

P.S. Just to step back from the problem a bit: Why can't you use D-
COM or CORBA for this? I think they both have mechanisms for
transplanting objects (i.e., moving a 'live' object from one server to
another and continuing its lifetime there). That's not exactly
serialization, but it might work.
 

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,581
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top