Topic: A humble attempt to improve "Move proposal
Author: dave@boost-consulting.com (David Abrahams)
Date: Wed, 30 Jul 2003 05:57:01 +0000 (UTC) Raw View
cxl@volny.cz ("Mirek Fidler") writes:
> This post attempts to improve important "Move proposal" present at
>
> http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1377.htm
>
> Suggested improvements try to cover two areas:
I'm just waiting for Howard to post the response he sent you privately
to your email. I think he addressed almost everything you raise here,
so it surprises me a little that you're posting it - especially the
claim that composition rules are missing in the original proposal,
which Howard aptly demonstrated to be false.
--
Dave Abrahams
Boost Consulting
www.boost-consulting.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: dhruvbird@gmx.net ("Dhruv")
Date: Wed, 30 Jul 2003 14:25:30 +0000 (UTC) Raw View
On Mon, 28 Jul 2003 17:42:00 +0000, Mirek Fidler wrote:
> This post attempts to improve important "Move proposal" present at
>
> http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1377.htm
>
> Suggested improvements try to cover two areas:
>
> (1) Instead of introducing new type of reference, it suggests recycling
> "mutable" keyword
> to introduce new type of CV-qualifier for function arguments. This
> should at least lead
> to elimination of completely redundant constructor form T(const T&&).
I wouldn't agree with overloading the 'mutable' keyword, because it would
just add to the confusion that already prevails. Just the other day, I ran
into trouble with void foo (void); thinking that the void parameter means
that it can take an argument of type void. When you first said:
void foo([volatile] mutable A& t); // #2
It came across as some type that is mutable, or which can be modified, or
is non-const. In fact, this applies only to non-const r-values ONLY (or to
something else???). I would like to see something like:
void foo([volatile] ncrv A& t); // #2
Meaning that (ncrv => Non-Const R-Value). Now, ncrv A& t means that you
are getting a non-const r-value as an argument, and you are accepting that
by reference. This could be extended to be:
ncrv A t, but it would be of little help.
Of cource, you cannot add const in front of ncrv, because ncrv itself
means that it is non-const.
The thinking behind this is similar to
reinterpret_cast<type_of_cast>(value_to_cast), wherein the coder is
reminded that he/she is about to do something dangerous. Similarly, ncrv
is not only difficult to type, but also does not rhyme with any word that
I know of, so it will keep reminding people of it's importance.
Regards,
-Dhruv.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: cxl@volny.cz ("Mirek Fidler")
Date: Wed, 30 Jul 2003 23:48:29 +0000 (UTC) Raw View
> void foo([volatile] mutable A& t); // #2
>
> It came across as some type that is mutable, or which can be modified,
or
> is non-const. In fact, this applies only to non-const r-values ONLY
No, it applies to non-const l-values as well. This is very similiar
to T& and const T& difference - you can bind non-const value to const
T&.... but T& has precedence.
> void foo([volatile] ncrv A& t); // #2
>
> Meaning that (ncrv => Non-Const R-Value). Now, ncrv A& t means that
you
> are getting a non-const r-value as an argument, and you are accepting
that
But in fact, both original move proposal and "mutable" version bind
even l-value to r-value reference / mutable reference.
Mirek
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: cxl@volny.cz ("Mirek Fidler")
Date: Thu, 31 Jul 2003 03:13:20 +0000 (UTC) Raw View
> so it surprises me a little that you're posting it - especially the
> claim that composition rules are missing in the original proposal,
Well, they are not exactly missing - as I understand original
proposal, it rules are "no implicit composition". I agree that it is
different from "missing compostion rules" :)
Mirek
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: cxl@volny.cz ("Mirek Fidler")
Date: Mon, 28 Jul 2003 17:42:00 +0000 (UTC) Raw View
This post attempts to improve important "Move proposal" present at
http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1377.htm
Suggested improvements try to cover two areas:
(1) Instead of introducing new type of reference, it suggests recycling
"mutable" keyword
to introduce new type of CV-qualifier for function arguments. This
should at least lead
to elimination of completely redundant constructor form T(const T&&).
(2) Second area, completely missing in original proposal, is an attempt
to introduce
composition rules which should apply when classes with combination of
move/copy
constructors are combined together as nonstatic data members and/or base
classes
of target class.
This attempt is made with full respect to original proposal and with
hope that some
form of explicit nondestructive move semantics will be present in
upcoming C++
standard.
Through text, [volatile] means that optional "volatile" qualifier may be
supplied.
(1) mutable as argument qualifier and resolution rules
------------------------------------------------------
Suggested complete "transfer-constructor" overload set:
void foo([volatile] const A& t); // #1
void foo([volatile] mutable A& t); // #2
void foo([volatile] A& t); // #3
The rules for overload resolution are:
Both constant rvalues and lvalues will bind to constant reference (1).
Non-constant rvalue will prefer 'mutable' reference (2), then const
reference (1).
Non-constant lvalues will prefer non-constant reference if available
(3),
then 'mutable' reference (2) and constant reference last (1).
(Alternatively, (2) can be dropped, resulting in less complex rules,
but constructor duplication).
Summary:
constant rvalue or lvalue -> 1
non-constant rvalue -> 2, 1
non-constant lvalue -> 3, 2, 1 (alternative: 3, 1)
Examples:
A source();
const A const_source();
A a;
const A ca;
foo(ca); // binds to #1
foo(a); // binds to #3
foo(source()); // binds to #2
foo(const_source()); // binds to #1
---------------------------------------
(2) Composition rules
---------------------
If there is no explicitly declared copy constructor of form T(const T&)
or T(T&),
compiler generates implicitly-defined one in form of
T(const T&) if all non-static data members and bases have accessible
unambiguous copy-constructor
of form T([volatile] const T&)
T(T &) if all non-static data members and bases have accessible
unambiguous copy-constructor
of form T([volatile] const T&) or T([volatile] T&).
The implicitly-defined copy constructor for class X performs a
memberwise copy of its subobjects
If there is no explicitly declared move constructor of form T(mutable
T&), compiler generates
implicitly-defined one if all non-static data members and bases have
public copy-constructor of
form T([volatile] const T&) or T([volatile] mutable T&).
The implicitly-defined move constructor performs a memberwise move if
move constructor (in
form M(mutable M&)) for specific member is present, copy (in form
M(const M&)) otherwise.
Example:
class Alfa {
Alfa(mutable Alfa&);
Alfa(const Alfa&);
};
class Beta {
Beta(mutable Beta& b);
};
struct C1 {
Alfa a;
int b;
// compiler generates C1(const C1&) and C1(mutable C1&)
};
struct C2 {
Beta a;
int b;
// compiler generates only C2(mutable C2&)
};
Same rules should apply to assignment operator.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: cxl@volny.cz ("Mirek Fidler")
Date: Tue, 29 Jul 2003 17:37:14 +0000 (UTC) Raw View
> (2) Composition rules
> If there is no explicitly declared copy constructor of form T(const
T&)
> or T(T&),
> If there is no explicitly declared move constructor of form T(mutable
> T&), compiler generates
As Howard Hinnant pointed out, above two sentences require
adjusting, otherwise existing code would be broken:
If there is no explicitly declared copy constructor *nor move
constructor*, compiler generates implicitly-defined one in form of....
If there is no explicitly declared move constructor *nor copy
constructor*, compiler generates...
So the proposed composition rules should be:
(2) Composition rules
---------------------
If there is no explicitly declared copy constructor nor move
constructor, compiler generates implicitly-defined one in form of
T(const T&) if all non-static data members and bases have accessible
unambiguous copy-constructor of form T([volatile] const T&)
T(T &) if all non-static data members and bases have accessible
unambiguous copy-constructor of form T([volatile] const T&) or
T([volatile] T&).
The implicitly-defined copy constructor for class X performs a
memberwise copy of its subobjects.
If there is no explicitly declared move constructor nor copy
constructor, compiler generates implicitly-defined one if all non-static
data members and bases have public copy-constructor of form T([volatile]
const T&) or T([volatile] mutable T&).
The implicitly-defined move constructor performs a memberwise move if
move constructor (in form M(mutable M&)) for specific member is present,
copy (in form M(const M&)) otherwise.
----------------------------------------------------
This has an advantage of being even safer than simple rules of original
proposal - reconsider move_ptr example again:
template<class X>
class move_ptr
{
public:
move_ptr(move_ptr&& a); // or move_ptr(mutable move_ptr& a);
.........
private:
move_ptr(const move_ptr& a);
};
Accidental omitting of move_ptr(const move_ptr& a); in private section
would lead in
incorect interface behaviour of move_ptr, while using altered
composition rules, this constructor simply does not get generated.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]