473,320 Members | 2,202 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,320 software developers and data experts.

Bug in C++ /CLI 2005

Greetings:

Is anyone aware of a fix for the apparent bug in C++ /CLI 2005...

If you create a class with a ref type member variable declared with stack semantics and you declare this member as [NonSerialized], when you deserialize an object of this class type, the member can no longer be used.

It is essentially orphaned.

Help...
Oct 4 '08 #1
30 1523
A bit more info... when I say essentially orphaned what I mean is that the magic that happens to make things declared with stack semantics get placed on the heap doesn't happen on deserialization if your member is attributed with NonSerialized. Also, because it is declared with stack semantics there is no longer any way to assign storage to it, thus orphaned.

Usually orphaned means that memory has been allocated and there is no longer anyway to refer to it. In this case I have a reference and no way to assign memory to it.
"Howard Swope" <howard_swopeAThms3DOTcomwrote in message news:%2****************@TK2MSFTNGP05.phx.gbl...
Greetings:

Is anyone aware of a fix for the apparent bug in C++ /CLI 2005...

If you create a class with a ref type member variable declared with stack semantics and you declare this member as [NonSerialized], when you deserialize an object of this class type, the member can no longer be used.

It is essentially orphaned.

Help...
Oct 4 '08 #2
"Howard Swope" <howard_swopeAThms3DOTcomwrote in message news:%2****************@TK2MSFTNGP05.phx.gbl...
I don't know if that's a bug or by design.

When the object is deserialized, a new object is created most likely NOT using stack semantics.

The member variable is still there, but it is uninitialized, probably because only code compiled with the C++ compiler is capable of using stack semantics to create objects.

I'd say the bug is allowing a member variable with stack semantics in the first place. It probably makes the class unusable outside of C++.

Mark

--
Mark Salsbery
Microsoft MVP - Visual C++
Greetings:

Is anyone aware of a fix for the apparent bug in C++ /CLI 2005...

If you create a class with a ref type member variable declared with stack semantics and you declare this member as [NonSerialized], when you deserialize an object of this class type, the member can no longer be used.

It is essentially orphaned.

Help...

Oct 4 '08 #3
Mark:

Declaring variables with stack semantics is one of the Advertised features in C++ CLI and a very useful one. For us it is especially useful because we have an unmanaged library of referenced counted objects that we use. We have created managed smart pointers to hold onto them and handle all the reference counting issues. The only real way to do this is by overloading all the pointer operators. This doesn't really work if you initialize them with gcnew. This is certainly not a feature. After deserialization there is no storage associated with the variable and no way to ever use the variable again. You can't use gcnew with a variable declared with stack semantics.

These smart pointers are essential to our code. I am supposed to release this product in 3 months and now it looks like I am going to have to manually implement ISerializable on a hunderd classes. I will have just made my code base magnitudes more error prone. If I don't get a work around for this, I am @#$_(_)+(++( 'd.
"Mark Salsbery [MVP]" <MarkSalsbery[MVP]@newsgroup.nospamwrote in message news:up**************@TK2MSFTNGP06.phx.gbl...
"Howard Swope" <howard_swopeAThms3DOTcomwrote in message news:%2****************@TK2MSFTNGP05.phx.gbl...
I don't know if that's a bug or by design.

When the object is deserialized, a new object is created most likely NOT using stack semantics.

The member variable is still there, but it is uninitialized, probably because only code compiled with the C++ compiler is capable of using stack semantics to create objects.

I'd say the bug is allowing a member variable with stack semantics in the first place. It probably makes the class unusable outside of C++.

Mark

--
Mark Salsbery
Microsoft MVP - Visual C++
Greetings:

Is anyone aware of a fix for the apparent bug in C++ /CLI 2005...

If you create a class with a ref type member variable declared with stack semantics and you declare this member as [NonSerialized], when you deserialize an object of this class type, the member can no longer be used.

It is essentially orphaned.

Help...

Oct 4 '08 #4
Howard Swope wrote:
Is anyone aware of a fix for the apparent bug in C++ /CLI 2005...

If you create a class with a ref type member variable declared with
stack semantics and you declare this member as [NonSerialized], when you
deserialize an object of this class type, the member can no longer be used.

It is essentially orphaned.
OK, you deserialize a class, but one of its members is marked and
[NonSerialized]. What do you expect the semantics of this member would
be? It cannot be deserialized, because you marked it so. I guess you
should either allow it to be deserialized and augment the data later, or
customize deserialization with your own code as to ignore this marking.

Feel free to ignore my advice, though. I personally think that C++/CLI
is devilishly difficult and only real experts in both domains C++ AND
..NET stand a chance to use it fluently. I'm not an expert in .NET by any
means.
B.
Oct 4 '08 #5
Thanks for the suggestion. I am at present exploring all my options.

If one marks a value type as NonSerialized it still has storage associated
with it after deserialization. It is just uninitialized. For example if you
had an int variable to which you assigned the value 5 and it was attributed
with NonSerialized. Upon deserialization the value is 0 as this is the value
given to an uninitialized integer. A reference type declared with stack
semantics needs to behave in the same fashion. Under the covers the
deserialization code needs to assign an uninitialized object of that type to
the variable.

I have tried to assign it storage in the OnDeserialized routine, something
like this...

//~~~~~~~~~~~~~~
// Declared previously as
[NonSerialized]
MyClass myClass;
//~~~~~~~~~~~~~~~~

void OnDeserialziation(Object^ sender)
{
%myClass = gcnew MyClass( ) // unfortunately it doesn't work like this.
}

I am going to put in a support call today at some point.

I agree that C++ / CLI is complex, but it is a wonderful tool to do what it
is designed for, to straddle the managed and unmanaged worlds. It is light
years ahead of its predecessor managed C++. It has a few bugs still to be
worked out, unfortunately mine is one of them. It makes interoperating
between the two worlds as painless as possible and I think is a very elegant
means of doing it. It is really quite remarkable the way that it allows you
to move, almost seamlessly, between managed and unmanaged. There are still
barriers that .Net imposes that it must work within. I would very much like
to be able to use unmanaged types as template parameters to managed classes
and I would very much like to be able to write inline assembler in an
unmanaged assembly. It is very unlikely that this will ever come to pass.
But, all in all a wonderful tool that I hope keeps evolving.

"Bronek Kozicki" <br**@spamcop.netwrote in message
news:uw**************@TK2MSFTNGP04.phx.gbl...
Howard Swope wrote:
>Is anyone aware of a fix for the apparent bug in C++ /CLI 2005...
If you create a class with a ref type member variable declared with
stack semantics and you declare this member as [NonSerialized], when you
deserialize an object of this class type, the member can no longer be
used.
It is essentially orphaned.

OK, you deserialize a class, but one of its members is marked and
[NonSerialized]. What do you expect the semantics of this member would be?
It cannot be deserialized, because you marked it so. I guess you should
either allow it to be deserialized and augment the data later, or
customize deserialization with your own code as to ignore this marking.

Feel free to ignore my advice, though. I personally think that C++/CLI is
devilishly difficult and only real experts in both domains C++ AND .NET
stand a chance to use it fluently. I'm not an expert in .NET by any means.
B.
Oct 4 '08 #6
>"Howard Swope" <howard_swopeAThms3DOTcomwrote in message news:Oy**************@TK2MSFTNGP02.phx.gbl...
>
>>Declaring variables with stack semantics is one of the Advertised features in C++ CLI
Not member variables.

It makes no sense to have member variables with stack semantics - there's no "stack" involved unless you have an actual object.

Stack semantics is just a C++ language feature. The syntax allows controlling the scope of a managed object (NOT class or member) using the more familiar (to C++ programmers) automatic variable (stack-based) syntax.
Under the hood an object created using stack semantics is still allocated on the managed heap with gcnew.
It ONLY works in C++. You can't possibly expect deserialize code from the framework to handle member variables declared with stack semantics properly.
And, as mentioned by others, you can't expect a member marked [NonSerialized] to be handled at ALL by the deserialize code in the framework.

Mark

--
Mark Salsbery
Microsoft MVP - Visual C++
Oct 4 '08 #7
>>"Howard Swope" <howard_swopeAThms3DOTcomwrote in message news:Oy**************@TK2MSFTNGP02.phx.gbl...
>>We have created managed smart pointers to hold onto them and
handle all the reference counting issues. The only real way to do this
is by overloading all the pointer operators. This doesn't really work if
you initialize them with gcnew.
I'm not understanding why stack based semantic member variables helps you here.

Objects of a ref class can ONLY be created on the managed heap, so why do
you think not using gcnew is even possible?

Why use a managed smart pointer ref class to hold an unmanaged pointer?
Seems to me, all you get from that is less control over the lifetime of your unmanaged objects.

Mark

--
Mark Salsbery
Microsoft MVP - Visual C++
Oct 4 '08 #8
http://msdn.microsoft.com/en-us/library/ms177191.aspx

Prior to Microsoft Visual C++ 2005, an instance of a reference type could only be created using the new operator, which created the object on the garbage collected heap. However, beginning in Microsoft Visual C++ 2005, you can create an instance of a reference type using the same syntax that you would use to create an instance of a native type on the stack. So, you do not need to use gcnew) to create an object of a reference type and that when the object goes out of scope, the compiler will call the object's destructor.

My class has member variables created with stack semantics and the they work fine except for deserialization. I understand that there is really no stack and that the object is being added to the managed heap. However, if you have a member variable declared with stack semantics marked NonSerializable, the underlying object is set to null during deserialization which is logical. But since the variable is not a syntactically a reference pointer it seems there is no possible way to ever have it be anything but null.

"Mark Salsbery [MVP]" <MarkSalsbery[MVP]@newsgroup.nospamwrote in message news:e4**************@TK2MSFTNGP04.phx.gbl...
>"Howard Swope" <howard_swopeAThms3DOTcomwrote in message news:Oy**************@TK2MSFTNGP02.phx.gbl...
>>Declaring variables with stack semantics is one of the Advertised features in C++ CLI
Not member variables.

It makes no sense to have member variables with stack semantics - there's no "stack" involved unless you have an actual object.

Stack semantics is just a C++ language feature. The syntax allows controlling the scope of a managed object (NOT class or member) using the more familiar (to C++ programmers) automatic variable (stack-based) syntax.
Under the hood an object created using stack semantics is still allocated on the managed heap with gcnew.
It ONLY works in C++. You can't possibly expect deserialize code from the framework to handle member variables declared with stack semantics properly.
And, as mentioned by others, you can't expect a member marked [NonSerialized] to be handled at ALL by the deserialize code in the framework.

Mark

--
Mark Salsbery
Microsoft MVP - Visual C++
Oct 4 '08 #9
The smart pointer class is wrapping an unmanaged pointer that is reference counted. In the unmanaged library we are using the objects are in charge of their own lifetime, very similar to the way COM does things. They have an IncrementRefCount and DecrementRefCount function. When the ref count gets to 0 the objects delete themselves. My smart pointer class overloads ->, *, ==, !=, and = oeprators to defer to the underlying unmanged pointer. Because I overload the -I can't really use it any other way besides declared with stack semantics. We use these reference counted objects everywhere and the managed pointers keep us from getting memory leaks.
"Mark Salsbery [MVP]" <MarkSalsbery[MVP]@newsgroup.nospamwrote in message news:eV*************@TK2MSFTNGP03.phx.gbl...
>>"Howard Swope" <howard_swopeAThms3DOTcomwrote in message news:Oy**************@TK2MSFTNGP02.phx.gbl...
We have created managed smart pointers to hold onto them and
handle all the reference counting issues. The only real way to do this
is by overloading all the pointer operators. This doesn't really work if
you initialize them with gcnew.
I'm not understanding why stack based semantic member variables helps you here.

Objects of a ref class can ONLY be created on the managed heap, so why do
you think not using gcnew is even possible?

Why use a managed smart pointer ref class to hold an unmanaged pointer?
Seems to me, all you get from that is less control over the lifetime of your unmanaged objects.

Mark

--
Mark Salsbery
Microsoft MVP - Visual C++
Oct 4 '08 #10
Here is a small project that demonstrates the issue. I did not include all the smart pointer stuff, so the example won't really illustrate why I want to do this, but it does show what I think is the bug.

http://www.hms3.com/download/CPPCLIConsole.zip

"Mark Salsbery [MVP]" <MarkSalsbery[MVP]@newsgroup.nospamwrote in message news:e4**************@TK2MSFTNGP04.phx.gbl...
>"Howard Swope" <howard_swopeAThms3DOTcomwrote in message news:Oy**************@TK2MSFTNGP02.phx.gbl...
>>Declaring variables with stack semantics is one of the Advertised features in C++ CLI
Not member variables.

It makes no sense to have member variables with stack semantics - there's no "stack" involved unless you have an actual object.

Stack semantics is just a C++ language feature. The syntax allows controlling the scope of a managed object (NOT class or member) using the more familiar (to C++ programmers) automatic variable (stack-based) syntax.
Under the hood an object created using stack semantics is still allocated on the managed heap with gcnew.
It ONLY works in C++. You can't possibly expect deserialize code from the framework to handle member variables declared with stack semantics properly.
And, as mentioned by others, you can't expect a member marked [NonSerialized] to be handled at ALL by the deserialize code in the framework.

Mark

--
Mark Salsbery
Microsoft MVP - Visual C++
Oct 4 '08 #11

"Howard Swope" <howard_swopeAThms3DOTcomwrote in message news:em**************@TK2MSFTNGP04.phx.gbl...
http://msdn.microsoft.com/en-us/library/ms177191.aspx

Prior to Microsoft Visual C++ 2005, an instance of a reference type could only be created using the new operator, which created the object on the garbage collected heap. However, beginning in Microsoft Visual C++ 2005, you can create an instance of a reference type using the same syntax that you would use to create an instance of a native type on the stack. So, you do not need to use gcnew) to create an object of a reference type and that when the object goes out of scope, the compiler will call the object's destructor.


Right. My point is, it's just semantics - which is probably why they called it stack semantics.

The code syntax is the same as a stack based (automatic) variable but the compiled code still needs to call gcnew.
A ref class object still needs to be created on the managed heap no matter what syntax you use.
As far as object lifetime management goes, there's no difference between

void somefunc()
{
SomeRefClass obj(...);
}

and

void somefunc()
{
SomeRefClass ^obj = gcnew SomeRefClass(...);
delete obj;
}
None of this applies to member variables.
I'll take a look at your code sample....I'll be back.
Cheers,
Mark

--
Mark Salsbery
Microsoft MVP - Visual C++
..
Oct 4 '08 #12
Thanks for the sample code!

I still see no benefit to using the stack semantics. It's not giving you any extra control over the object's lifetime - if anything, it takes away control.

You've already derived from IDeserializationCallback.... why not just change the NonSerialized member variable(s) to managed handles and gcnew them in the OnDeserialization() override?

Mark

--
Mark Salsbery
Microsoft MVP - Visual C++

"Howard Swope" <howard_swopeAThms3DOTcomwrote in message news:Op*************@TK2MSFTNGP04.phx.gbl...
Here is a small project that demonstrates the issue. I did not include all the smart pointer stuff, so the example won't really illustrate why I want to do this, but it does show what I think is the bug.

http://www.hms3.com/download/CPPCLIConsole.zip

Oct 4 '08 #13
I think I addressed this in reply to another one of your posts when asking about the smart pointers I said...

The smart pointer class is wrapping an unmanaged pointer that is reference counted. In the unmanaged library we are using the objects are in charge of their own lifetime, very similar to the way COM does things. They have an IncrementRefCount and DecrementRefCount function. When the ref count gets to 0 the objects delete themselves. My smart pointer class overloads ->, *, ==, !=, and = oeprators to defer to the underlying unmanged pointer. Because I overload the -I can't really use it any other way besides declared with stack semantics. We use these reference counted objects everywhere and the managed pointers keep us from getting memory leaks.

If not for the smart pointers I would do just that. The operator overloads reclude this.
"Mark Salsbery [MVP]" <MarkSalsbery[MVP]@newsgroup.nospamwrote in message news:Oh**************@TK2MSFTNGP03.phx.gbl...
Thanks for the sample code!

I still see no benefit to using the stack semantics. It's not giving you any extra control over the object's lifetime - if anything, it takes away control.

You've already derived from IDeserializationCallback.... why not just change the NonSerialized member variable(s) to managed handles and gcnew them in the OnDeserialization() override?

Mark

--
Mark Salsbery
Microsoft MVP - Visual C++

"Howard Swope" <howard_swopeAThms3DOTcomwrote in message news:Op*************@TK2MSFTNGP04.phx.gbl...
Here is a small project that demonstrates the issue. I did not include all the smart pointer stuff, so the example won't really illustrate why I want to do this, but it does show what I think is the bug.

http://www.hms3.com/download/CPPCLIConsole.zip

Oct 4 '08 #14
Hey Mark:

http://www.hms3.com/download/CPPCLIConsole.zip

I updated the sample code to show a smart pointer class. I think when you see this, the reason behind why I want to do this becomes clear. This has been a good exercise as I will have to explain this to MS support on Monday.

Thanks for your comments.

"Mark Salsbery [MVP]" <MarkSalsbery[MVP]@newsgroup.nospamwrote in message news:Oh**************@TK2MSFTNGP03.phx.gbl...
Thanks for the sample code!

I still see no benefit to using the stack semantics. It's not giving you any extra control over the object's lifetime - if anything, it takes away control.

You've already derived from IDeserializationCallback.... why not just change the NonSerialized member variable(s) to managed handles and gcnew them in the OnDeserialization() override?

Mark

--
Mark Salsbery
Microsoft MVP - Visual C++

"Howard Swope" <howard_swopeAThms3DOTcomwrote in message news:Op*************@TK2MSFTNGP04.phx.gbl...
Here is a small project that demonstrates the issue. I did not include all the smart pointer stuff, so the example won't really illustrate why I want to do this, but it does show what I think is the bug.

http://www.hms3.com/download/CPPCLIConsole.zip

Oct 4 '08 #15
Howard Swope wrote:
If you create a class with a ref type member variable declared with
stack semantics and you declare this member as [NonSerialized], when you
deserialize an object of this class type, the member can no longer be used.
An member object with stack semantics must be initialized in a
constructor. But if you use default serialization, no constructor is
called. It's as simple (and as bad) as that.

IMO, it's a design error in the .NET framework not to call any
constructor when deserializing an object. At least an optional special
constructor should have been introduced (similar to the one used if the
ISerializable interface is implemented).

And it seems that the designers of C++/CLI didn't think of that case, or
they thought that anyone who uses a member object with stack semantics
will implement ISerializable.

In your case, if the smart pointer class is actually a template (as it
should be, but contrary to the example code you provided) and if it is
possible for you to always create the native objects through a default
constructor (or another constructor with always the same signature), an
easy workaround would be to let the smart pointer class implement
ISerializable and pseudo-serialize it, i.e. remove the [NonSerialized]
attribute.

BTW: calling native code from a finalizer is dangerous. I hope you know
what you're doing and e.g. the ref count of the native object is thread
safe (and its destructor, too, I presume). On the other hand, if you're
always using stack semantic, each smart pointer will be disposed
automatically, and the finalizer is unnecessary anyway.

Joerg
--
"Quoth the raven: Nevermore!" -- E.A.Poe
Oct 8 '08 #16
Mark Salsbery [MVP] wrote:
>"Howard Swope" <howard_swopeAThms3DOTcomwrote in message
news:Oy**************@TK2MSFTNGP02.phx.gbl...
>>Declaring variables with stack semantics is one of the Advertised
features in C++ CLI

Not member variables.

It makes no sense to have member variables with stack semantics -
there's no "stack" involved unless you have an actual object.
I definitely do NOT agree with this. Stack semantics give you all the
correct calls to Dispose in all the corner cases, like exceptions thrown in
constructor initializer lists, automatically. Stack semantics is perhaps
not the best description -- scoped variable lifetime (vs dynamic lifetime)
might be better.
Oct 9 '08 #17
Howard Swope wrote:
Thanks for the suggestion. I am at present exploring all my options.

If one marks a value type as NonSerialized it still has storage
associated with it after deserialization. It is just uninitialized.
For example if you had an int variable to which you assigned the
value 5 and it was attributed with NonSerialized. Upon
deserialization the value is 0 as this is the value given to an
uninitialized integer. A reference type declared with stack semantics
needs to behave in the same fashion. Under the covers the
deserialization code needs to assign an uninitialized object of that
type to the variable.
The compiler-generated code added to each constructor should initialize that
variable. It sounds as if deserialization creates an object without calling
any constructor? This is broken. With no constructor call, there is no
object instance, the lifetime has not started, and you can't safely use it
at all.
Oct 9 '08 #18
"Ben Voigt [C++ MVP]" <rb*@nospam.nospamwrote in message
news:ex**************@TK2MSFTNGP05.phx.gbl...
Mark Salsbery [MVP] wrote:
>>"Howard Swope" <howard_swopeAThms3DOTcomwrote in message
news:Oy**************@TK2MSFTNGP02.phx.gbl...

Declaring variables with stack semantics is one of the Advertised
features in C++ CLI

Not member variables.

It makes no sense to have member variables with stack semantics -
there's no "stack" involved unless you have an actual object.

I definitely do NOT agree with this. Stack semantics give you all the
correct calls to Dispose in all the corner cases, like exceptions thrown
in constructor initializer lists, automatically. Stack semantics is
perhaps not the best description -- scoped variable lifetime (vs dynamic
lifetime) might be better.
Hi Ben,

How does scoped variable lifetime apply to member variables?
The scoped variable lifetime of a member variable is determined by it's
containing class, right?

For this to work, the compiler would need to generate the gcnew calls for
the member variables. That means one would be stuck with a parameterless
constructor, unless some (possibly obscure) construct syntax was added to
the language to allow other constructor calls for these "automatic"
variables.

I imagine a similar argument occurred when this feature of the language was
designed. :)

Is it a bug or by design?

I still think, given the way it currently works, that stack semantics on ref
class member variables shouldn't be allowed.

Mark

--
Mark Salsbery
Microsoft MVP - Visual C++

Oct 9 '08 #19
"Ben Voigt [C++ MVP]" <rb*@nospam.nospamwrote in message
news:uY*************@TK2MSFTNGP06.phx.gbl...
>
The compiler-generated code added to each constructor should initialize
that variable. It sounds as if deserialization creates an object without
calling any constructor? This is broken.

That's documented, as-designed behavior (right or wrong).

If a constructor was called we wouldn't be having this discussion I suppose
:)

Mark

--
Mark Salsbery
Microsoft MVP - Visual C++


Oct 9 '08 #20
Mark Salsbery [MVP] wrote:
"Ben Voigt [C++ MVP]" <rb*@nospam.nospamwrote in message
news:ex**************@TK2MSFTNGP05.phx.gbl...
>Mark Salsbery [MVP] wrote:
>>>"Howard Swope" <howard_swopeAThms3DOTcomwrote in message
news:Oy**************@TK2MSFTNGP02.phx.gbl...

Declaring variables with stack semantics is one of the Advertised
features in C++ CLI

Not member variables.

It makes no sense to have member variables with stack semantics -
there's no "stack" involved unless you have an actual object.

I definitely do NOT agree with this. Stack semantics give you all
the correct calls to Dispose in all the corner cases, like
exceptions thrown in constructor initializer lists, automatically. Stack
semantics is perhaps not the best description -- scoped
variable lifetime (vs dynamic lifetime) might be better.

Hi Ben,

How does scoped variable lifetime apply to member variables?
The scoped variable lifetime of a member variable is determined by
it's containing class, right?

For this to work, the compiler would need to generate the gcnew calls
for the member variables. That means one would be stuck with a
parameterless constructor, unless some (possibly obscure) construct
syntax was added to the language to allow other constructor calls for
these "automatic" variables.
Whoa, is someone impersonating the real Mark, the C++ MVP? Or are you just
having an off day?

Because ctor initializer-lists are hardly obscure and fully standard. I
even mentioned them in my post.

The same thing effectively happens for members of native types which take
parameters to their constructors, except it's use of placement new vs gcnew,
and the managed type isn't actually inside the containing class (although
they will be placed contiguously in memory under the most obvious
implementation of the managed heap, which is a stack not a heap anyway).
>
I imagine a similar argument occurred when this feature of the
language was designed. :)

Is it a bug or by design?

I still think, given the way it currently works, that stack semantics
on ref class member variables shouldn't be allowed.

Mark

Oct 9 '08 #21
Mark Salsbery [MVP] wrote:
"Ben Voigt [C++ MVP]" <rb*@nospam.nospamwrote in message
news:uY*************@TK2MSFTNGP06.phx.gbl...
>>
The compiler-generated code added to each constructor should
initialize that variable. It sounds as if deserialization creates
an object without calling any constructor? This is broken.


That's documented, as-designed behavior (right or wrong).
We can argue about terms like "right" and "wrong", but that's singularly
useless. The C++ way (enshrined in the ISO standard) is that an object's
life doesn't begin until its constructor finishes executing. So
deserialization creates dead objects that aren't safe to use.
>
If a constructor was called we wouldn't be having this discussion I
suppose :)

Mark

Oct 9 '08 #22
"Ben Voigt [C++ MVP]" <rb*@nospam.nospamwrote in message
news:#d**************@TK2MSFTNGP05.phx.gbl...
Whoa, is someone impersonating the real Mark, the C++ MVP? Or are you
just having an off day?

Heh :) I'm impersonating me!
>
Because ctor initializer-lists are hardly obscure and fully standard. I
even mentioned them in my post.

I can't really be expected to read everything, can I? :)

I'm fully in binary deserialization mode here, so constructors were never
relevant to me in this thread.

I am, however, now following what you're saying.

I still don't like it. I like it in C#, but in C++ I want to see the "^" on
my ref type members.
That's my preference, but I withdraw my statements about stack-semantics
member variables being useless.

They don't work so well with deserialization, however.

I'm going with "having an off day" :)

Thanks Ben!

Cheers,
Mark

--
Mark Salsbery
Microsoft MVP - Visual C++


Oct 10 '08 #23
"Ben Voigt [C++ MVP]" <rb*@nospam.nospamwrote in message
news:#R*************@TK2MSFTNGP03.phx.gbl...
We can argue about terms like "right" and "wrong", but that's singularly
useless. The C++ way (enshrined in the ISO standard) is that an object's
life doesn't begin until its constructor finishes executing.

This is C++/CLI, not ISO standard C++.

So deserialization creates dead objects that aren't safe to use.

That even SOUNDS wrong!

That means I use a LOT of unsafe dead objects in my apps (I use .NET
serialization extensively) :)
Cheers,
Mark
--
Mark Salsbery
Microsoft MVP - Visual C++

Oct 10 '08 #24


"Mark Salsbery [MVP]" <MarkSalsbery[MVP]@newsgroup.nospamwrote in message
news:#v**************@TK2MSFTNGP04.phx.gbl...
"Ben Voigt [C++ MVP]" <rb*@nospam.nospamwrote in message
news:#R*************@TK2MSFTNGP03.phx.gbl...
>We can argue about terms like "right" and "wrong", but that's singularly
useless. The C++ way (enshrined in the ISO standard) is that an object's
life doesn't begin until its constructor finishes executing.


This is C++/CLI, not ISO standard C++.
I know, but C++/CLI was supposed to be an attempt to map the CLI as closely
as possible to C++. Having objects come alive without a constructor call is
a serious violation of that ideal.

It also means that the BCL serializers are doing things that can't be
duplicated by user libraries (I previously thought serialization was just
using reflection a bunch and maybe dynamically emitting methods with
lightweight codegen to reduce the overhead of repeated calls, something you
or I could do if we wanted). That's also against C++ thinking.
>
>So deserialization creates dead objects that aren't safe to use.


That even SOUNDS wrong!

That means I use a LOT of unsafe dead objects in my apps (I use .NET
serialization extensively) :)
Cheers,
Mark
--
Mark Salsbery
Microsoft MVP - Visual C++
Oct 10 '08 #25
>So deserialization creates dead objects that aren't safe to use.
>

That even SOUNDS wrong!

That means I use a LOT of unsafe dead objects in my apps (I use .NET
serialization extensively) :)
I can't find anything in the ECMA standard for C++/CLI that allows an object
instance to be created without a constructor call.

12.2.2 "Instances of ref classes are created using new-expressions
(§15.4.6)." (15.4.6 is gcnew)
F.3.1 "The object's lifetime begins when all construction is successfully
completed. For the purposes of the C++ Standard (§3.8), "the constructor
call has completed" means the originally invoked constructor call.
[Rationale: Even if a target constructor completes, an outer delegating
constructor can still throw an exception, and if so the caller did not get
the object that was requested. The foregoing decision also preserves the
Standard C++ rule that an exception emitted from a constructor means that
the object's lifetime never began. end rationale]"

Clearly C++/CLI intends to use the same rules for object lifetime as ISO
C++. Deserialized objects whose constructor was never called are not
legitimate C++/CLI objects.

I understand that's probably a big "Ouch!" and we should bring this up with
the C++/CLI language team.

Shucks, even an object that is a member of another object (that's the "stack
semantic members" we're talking about) seems to violate 12.2.2 even though
the constructor is properly called.

Then we have section 13.3 on initialization
"Direct initialization in the C++ Standard (§8.5) occurs in new expressions,
static_cast expressions,
functional notation type conversions, and base and member initializers."

And here in section 19.12 we find something probably related to this
deserialization bug:
"The type of an initonly field shall not be a ref class."
>

Cheers,
Mark
--
Mark Salsbery
Microsoft MVP - Visual C++

Oct 10 '08 #26
Mark Salsbery [MVP] wrote:
That means I use a LOT of unsafe dead objects in my apps (I use .NET
serialization extensively) :)
Mark:

And then there are the "half-dead" objects that have been Dispose'd but not GC'd.

--
David Wilkinson
Visual C++ MVP
Oct 10 '08 #27
"David Wilkinson" <no******@effisols.comwrote in message
news:uF**************@TK2MSFTNGP02.phx.gbl...
Mark Salsbery [MVP] wrote:
>That means I use a LOT of unsafe dead objects in my apps (I use .NET
serialization extensively) :)

Mark:

And then there are the "half-dead" objects that have been Dispose'd but
not GC'd.

Well half-dead sounds better than dead LOL.

I really need to look into this closely.
And Ben, I've seen your comments as well...I just haven't quite got to this
yet today.
Mark

--
Mark Salsbery
Microsoft MVP - Visual C++

>
--
David Wilkinson
Visual C++ MVP
Oct 10 '08 #28
Ben Voigt [C++ MVP] wrote:
It also means that the BCL serializers are doing things that can't be
duplicated by user libraries (I previously thought serialization was
just using reflection a bunch and maybe dynamically emitting methods
with lightweight codegen to reduce the overhead of repeated calls,
something you or I could do if we wanted).
No, user serializers can also do that. They've just got to use the
method FormatterServices::GetSafeUninitializedObject.

MSDN:
http://msdn.microsoft.com/en-us/libr...zedobject.aspx

"Because the new instance of the object is initialized to zero and no
constructors are run, the object might not represent a state that is
regarded as valid by that object. GetSafeUninitializedObject should only
be used for deserialization when the user intends to immediately
populate all fields."

Joerg
--
"Quoth the raven: Nevermore!" -- E.A.Poe
Oct 11 '08 #29
Joerg Ruedenauer wrote:
Ben Voigt [C++ MVP] wrote:
>It also means that the BCL serializers are doing things that can't be
duplicated by user libraries (I previously thought serialization was
just using reflection a bunch and maybe dynamically emitting methods
with lightweight codegen to reduce the overhead of repeated calls,
something you or I could do if we wanted).

No, user serializers can also do that. They've just got to use the
method FormatterServices::GetSafeUninitializedObject.

MSDN:
http://msdn.microsoft.com/en-us/libr...zedobject.aspx

"Because the new instance of the object is initialized to zero and no
constructors are run, the object might not represent a state that is
regarded as valid by that object. GetSafeUninitializedObject should
only be used for deserialization when the user intends to immediately
populate all fields."
Ugly, but understandable. There's another method on that class,
PopulateObjectMembers, does that allow you to set "initonly" fields of that
uninitialized object?

Can you override serialization so that placement new is called on the object
in between GetSafeUninitializedObject and PopulateObjectMembers, so that the
required constructor call is made? No, because I seem to recall there is no
placement gcnew. Maybe there's another way to explicitly call a
constructor.
>
Joerg

Oct 13 '08 #30
Ben Voigt [C++ MVP] schrieb:
Ugly, but understandable. There's another method on that class,
PopulateObjectMembers, does that allow you to set "initonly" fields of that
uninitialized object?
Yes, indeed it does.
Can you override serialization so that placement new is called on the object
in between GetSafeUninitializedObject and PopulateObjectMembers, so that the
required constructor call is made? No, because I seem to recall there is no
placement gcnew. Maybe there's another way to explicitly call a
constructor.
Not as far as I am aware. The usual strategy would be to implement
ISerializable if a constructor call is needed.

Joerg
--
"Quoth the raven: Nevermore!" -- E.A.Poe
Oct 14 '08 #31

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
by: DolphinDB | last post by:
The formulas of 101 quantitative trading alphas used by WorldQuant were presented in the paper 101 Formulaic Alphas. However, some formulas are complex, leading to challenges in calculation. Take...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
0
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.