Automatic deterministic destruction (for non-memory resource) is
regarded as an excellent design in C++/CLI, I agree on this, it is
better than C#'s "using" keyword, and better better than Java's
hard-coded dispose.
But, this feature is supported by the stack-based object in C++/CLI.
That's the problem.
#1. The stack-based object is pseudo stack-based
Yes, the stack-based object is still a managed-heap object, provided
that the type is ref class. It is still allocated from the managed heap
(using newobj IL instruction). It means the following two lines will
produce the same IL codes, if there is no destructor(~R) defined in
class R:
R r;
R h=gcnew R;
I remeber Herb Sutter had said they may allocate the "r" object from
the real stack in future. For now, they just want programmers to "feel
like" it is allocated from the stack.
OK, "feel like" is not so bad, although they may confuse some
programmers ( especially when using the managed address of operator %
on a stack-based object).
#2. copy constructor & copy assignment operator are not produced by
default
The big problem is that , by default, C++/CLI compiler does not produce
the copy constructor & copy assignment operator like ISO-C++. And the
more worse is that the existing types in Base Class Library have no
copy constructors or copy assignment operators at all.
This will hurt the usability of stack-based objects, no?
#3. We can not design a public function using stack-based object as its
parameter in C++/CLI
When a function uses a stack-based object as its parameter
(a) If the parameter is passed by-value, the function can be invoked by
other CLI languages (like C#, VB.NET, Delphi.NET, etc.) , like using a
handle as the parameter (because "IsByValue" has the optional modifier
"modopt" , although other CLI languages do not support the concept of
stack-based objects .)
For example, In C++/CLI, we declare a function in a ref class MyClass
as following:
static void add(R r){...}
In C++/CLI, we can invoke it as following (provided that R has a copy
constructor):
R r;
MyClass::add(r);
In C#, we can invoke it as following:
R r=new R();
MyClass.add(r);
The two code blocks look very similar, but the results are totally
different. The C++/CLI code blocks will invoke a copy constructor to
create a new object before passing the argument. While the C# code
blocks will just pass the handle "r" into the function. So if the "add"
function changes the members' value of parameter "r", after the
invocation, the object r's value will be unchanged in C++/CLI, while
the object which handle "r" points to will be changed in C#.
This kind of difference is unacceptable.
(b) If the parameter is passed by-reference, for example:
static void add(R% r){...}
The function can not be invoked by other CLI languages (because
"IsImplicitlyDereferenced" has the required modifier "modreq")
#4. We can not design a public function using stack-based object as its
return value in C++/CLI.
When a function returns a stack-based object
(a) If the return value is passed by-value, for example:
static R add(){...}
The function can not be invoked by other CLI languages (because
"IsUdtReturn" has the required modifier "modreq")
(b) If the return value is passed by-reference, for example:
static R% add(){...}
The function can not be invoked by other CLI languages (because
"IsImplicitlyDereferenced" has the required modifier "modreq")
#5. When we use Base Class Library, and pass a stack-based object as an
argument, we should always use the managed address-of operator "%"
For example:
String s("abc");
ArrayList list;
list.Add(%s);
Although using % for every argument looks ugly, but it can work after
all. Not so bad.
To summarize,
Item 1, and Item 5 will have a little influence on the usability of
stack-based objects.
Item 2, Item 3, and Item 4 will have considerable influence on the
usability of stack-based objects.
So , in order to get the good feature of automatic deterministic
destruction, is C++/CLI necessary to provide the stack-based objects
for ref class ?
Another design consideration of stack-based objects may be the symmetry
with ISO-C++, symmetry is beautiful. But here for stack-based objects,
I doubt the symmetry's value.
If you were the designer of C++/CLI, how do you make design on this ?
Jason.Li
http://blog.dreambrook.com/jzli/
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
lijianzhong79 (1)
|
1/6/2005 7:26:46 PM |
|
On 6 Jan 2005 14:26:46 -0500, "jason.li" <lijianzhong79@gmail.com> wrote:
>Automatic deterministic destruction (for non-memory resource) is
>regarded as an excellent design in C++/CLI, I agree on this, it is
>better than C#'s "using" keyword, and better better than Java's
>hard-coded dispose.
Thanks.
>#1. The stack-based object is pseudo stack-based
>
>Yes, the stack-based object is still a managed-heap object, provided
>that the type is ref class. It is still allocated from the managed heap
>(using newobj IL instruction). It means the following two lines will
>produce the same IL codes, if there is no destructor(~R) defined in
>class R:
>
>R r;
>R h=gcnew R;
There there's no destructor, then those already mean the same thing
because such a type doesn't do anything special for automatic lifetime
semantics. If there is a destructor, then R r; will give full automatic
lifetime semantics.
>I remeber Herb Sutter had said they may allocate the "r" object from
>the real stack in future. For now, they just want programmers to "feel
>like" it is allocated from the stack.
The main implementation will always be to put it on the gc heap, and
that's how it always is in this release, right. But that doesn't matter to
the programmer, who always gets automatic lifetime semantics. Where we put
the object is a layout detail that doesn't matter semantically. One
potential future layout choice would be for the compiler to notice when an
R object really is only used locally in which case it could potentially
physically lay out the R object memberwise on the stack, just for kicks.
We never do that in the release now in beta, but it's possible we might do
that sort of thing in the future.
>OK, "feel like" is not so bad, although they may confuse some
>programmers ( especially when using the managed address of operator %
>on a stack-based object).
It's semantically the same as using the native address of operator & on a
stack-based object.
>#2. copy constructor & copy assignment operator are not produced by
>default
>
>The big problem is that , by default, C++/CLI compiler does not produce
>the copy constructor & copy assignment operator like ISO-C++. And the
>more worse is that the existing types in Base Class Library have no
>copy constructors or copy assignment operators at all.
Those are exactly the ISO C++ rules, so you just answered your own
question. :-)
As you note, CLI reference types aren't valuelike; they aren't copyable.
So the key thing to notice is this: When you inherit from them, you're
inheriting from a base class that doesn't have a(n accessible) copy
constructor or copy assignment operator. The ISO C++ rule in that case is
to not generate them in the derived class (see 12.8/7,12); you'll get an
error if you try to call them.
>This will hurt the usability of stack-based objects, no?
Only if you try to make copies or pass such types by value. But you
already can't do those things with BCL reference objects because of the
way they were written (although you can pass around ^'s to them all you
like). Of course, with C++ you can additionally write reference objects
that can be copied.
>#3. We can not design a public function using stack-based object as its
>parameter in C++/CLI
>
>When a function uses a stack-based object as its parameter
>
>(a) If the parameter is passed by-value, the function can be invoked by
>other CLI languages (like C#, VB.NET, Delphi.NET, etc.) , like using a
>handle as the parameter (because "IsByValue" has the optional modifier
>"modopt" , although other CLI languages do not support the concept of
>stack-based objects .)
No, this isn't a problem because we do put it out as a modreq (other
languages are "req"uired to understand/enforce the extension's semantics
or else they cannot use the function). Maybe this was put out as modopt by
accident in the first beta? I don't know if it was, but if so that's been
fixed.
>#4. We can not design a public function using stack-based object as its
>return value in C++/CLI.
>
>When a function returns a stack-based object
>
>(a) If the return value is passed by-value, for example:
>
>static R add(){...}
>
>The function can not be invoked by other CLI languages (because
>"IsUdtReturn" has the required modifier "modreq")
Sure, other CLI languages don't understand value semantics, and if you
want to work with those you just return an R^ to a gcnew'd object. But C++
does allow you to write reference types that are copyable, and the above
code works just fine inside C++.
I don't see this as an issue about stack-based lifetime. There are other
power features C++ lets you use that other languages don't -- including
access to more CLI features(!) than other CLI languages choose to support.
You just need to decide whether you need to be interoperable with other
languages. If you don't, use all the C++ features to your heart's content.
If you do, then STILL use all the C++ features to your heart's content
inside your code, and only on the publicly exposed boundary of your code
that other modules talk to you can restrict yourself to what other
languages you care about will understand (perhaps the Common Language
Subset (CLS), which other languages are guaranteed to handle, or
CLS+something if you know the specific languages you care about all
understand more features than just CLS).
Herb
---
Herb Sutter (www.gotw.ca) (www.pluralsight.com/blogs/hsutter)
Convener, ISO WG21 (C++ standards committee) (www.gotw.ca/iso)
Contributing editor, C/C++ Users Journal (www.gotw.ca/cuj)
Architect, Developer Division, Microsoft (www.gotw.ca/microsoft)
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Herb
|
1/7/2005 3:06:05 PM
|
|
Thanks for Herb's brilliant reply.
The issue of 3.a should be a bug of compiler.
But as for #2. copy constructor & copy assignment operator are not
produced by default.
can I say if the BCL is written in C++/CLI, it will be better?
In other words, it is the BCL that hurts the usability of "stack-based"
object.
Although the "stack-based" object is not perfect, but I do believe the
overall design of C++/CLI is successful. especially the interior_ptr
and templates/stl.net are very excellent. They make C++/CLI so
larruping:)
Thanks for you and your team's great work!
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
jason
|
1/10/2005 8:29:33 PM
|
|
|
2 Replies
387 Views
(page loaded in 0.071 seconds)
|