Topic: Using the copy constructor for moving


Author: dave@boost-consulting.com (David Abrahams)
Date: Wed, 23 Jul 2003 19:03:44 +0000 (UTC)
Raw View
cxl@volny.cz ("Mirek Fidler") writes:

>> C++ has no unreserved keywords, and introducing one would make the
>> language yet more inconsistent.
>>
>> How about declaring the move constructor as:
>>
>>     class-name(~class-name parameter-name);
>>     class-name & operator=(~class-name parameter-name);
>>
>> with the ~ hinting that the other instance is about to be destroyed?
>
>     Well, the problem is that other instance is not destroyed

It is, when it's an rvalue.

>  - just its *content* *might* get "lost" - this is important
> difference.

The only memnonic problem with the above is that these references
also bind to lvalues, which are not neccessarily "about to be
destroyed".

>     I think that in reality, move constructor should rather indicate
> that other instance can be changed and that it can be a rvalue.
> Personally (I will repeat myself before get noticed :) I think
>
>     T(mutable T&);
>
>     syntax describes this situation best - it indicates that the other
> instance is about to be changed.

But it doesn't indicate that it might be an rvalue, a key feature of
the rvalue reference.  However, && isn't memnonic for anything other
than "is a reference".  None of the move proposers is in love
with "&&" AFAIK.

Hmm, now that I think about it, I like it!  I think it *does*
indicate possible rvalue-ness in a strange way, since mutable says
"even when x is const, you can change it".  So it's like const T& x
where x is changeable.  Not bad.

--
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: dave@boost-consulting.com (David Abrahams)
Date: Wed, 23 Jul 2003 19:03:58 +0000 (UTC)
Raw View
francis@robinton.demon.co.uk (Francis Glassborow) writes:

> So there is nothing to prevent us from creating another incomplete
> type (along side void):
>
> namespace std {
>    class move;
> }
>
> and then allocating it some special semantic meaning.

I don't see how that helps; you need to get another type into the
signature next to it.

Maybe a special template would work:

  namespace std { template <class T> struct move; }

  void f(std::move<T> x);

wow, looks Mojo-ish.

Overall, I think it seems quite brittle.  I prefer Mirek's "mutable"
idea now.

--
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: dave@boost-consulting.com (David Abrahams)
Date: Thu, 24 Jul 2003 18:05:38 +0000 (UTC)
Raw View
dave@boost-consulting.com (David Abrahams) writes:

> But it doesn't indicate that it might be an rvalue, a key feature of
> the rvalue reference.  However, && isn't memnonic for anything other
> than "is a reference".  None of the move proposers is in love
> with "&&" AFAIK.
>
> Hmm, now that I think about it, I like it!  I think it *does*
> indicate possible rvalue-ness in a strange way, since mutable says
> "even when x is const, you can change it".  So it's like const T& x
> where x is changeable.  Not bad.

Err, now I don't like it any more.  Howard pointed out to me that when
you pass a constant rvalue or lvalue through an rvalue reference
parameter, the result is constant inside the called function.
"mutable" seems to indicate the opposite will happen.

--
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: cxl@volny.cz ("Mirek Fidler")
Date: Mon, 28 Jul 2003 17:39:45 +0000 (UTC)
Raw View
> >     Well, the problem is that other instance is not destroyed
>
> It is, when it's an rvalue.

    Yes, but not by the constructor nor '&&'.... At least as I
understand proposal. It is about non-destructive moves, is not it ?

> >     I think that in reality, move constructor should rather indicate
> > that other instance can be changed and that it can be a rvalue.
> > Personally (I will repeat myself before get noticed :) I think
> >
> >     T(mutable T&);
> >
> >     syntax describes this situation best - it indicates that the
other
> > instance is about to be changed.
>
> Hmm, now that I think about it, I like it!  I think it *does*
> indicate possible rvalue-ness in a strange way, since mutable says
> "even when x is const, you can change it".  So it's like const T& x
> where x is changeable.  Not bad.

    Oh, I hope it is even a little bit more more expressive. First of
all, rvalues are not consts - they ARE mutable. So for the whole set

    T(T&)   - source has to be lvalue
    T(const T&) - source can be anything (but cannot be changed)
    T(mutable T&) - source can be anything other than const - that I
believe includes the most important case - temporaries.

    And, last but not least, "mutable" in present C++ marks things as
"watch out, strange things are happening here" :)

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:41:34 +0000 (UTC)
Raw View
> Err, now I don't like it any more.  Howard pointed out to me that when
> you pass a constant rvalue or lvalue through an rvalue reference
> parameter, the result is constant inside the called function.
> "mutable" seems to indicate the opposite will happen.

    Then I am sorry. I missed that you plan to pass constant rvalues
throught '&&'. You mean something like

T(const T&& x)

    ???

    If this is the case, may I ask what is the benefit of this variant ?
Constructor taking const parameter cannot be of course moving....

    Well, problem maybe is that the proposal introduces a new type of
reference, whereas this syntax would rather introduce a new type of
access specifier for function parameters. I will have to read the
proposal more carefuly to find out difference between two variants and
the real need for introducing new type of 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: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Tue, 22 Jul 2003 04:37:49 GMT
Raw View
In message <8665lzln01.fsf@Zorthluthik.local.bar>, llewelly
<llewelly.at@xmission.dot.com> writes
>When I read your proposal, I couldn't help but think of the
>    bit in D&E where Stroustrup mentions a scheme for exception syntax
>    that used the keyword 'catch' in place 'try', 'throw' and of
>    course 'catch' as well - a scheme he '... despaired of explaining
>    ...' I fear bar(bar&&) is of similar nature.
>
>C++ already has too much confusing syntax. Let's make sure new
>    syntax doesn't fall in line behind the likes of foo()=0,
>    operator++(int), and so forth.
>
>(I don't mention Andrei's syntax, because, despite the fact that I
>    admire him greatly, I consider his 'bar(bar)' to be even more
>    confusing than 'bar(bar&&)' .)

As I see it the major problem is the continued view of ctors as
functions. Considering that they (officially) are nameless and certainly
have no return values they clearly are unlike any other C++ entities.
Even dtors can be called.

Given that this is the case, I think we might reasonably explore syntax
choices for move ctors that are special and do not generalise to other
entities.

Now I am not by any stretch of the imagination knowledgeable about
compilers but I am still going to indulge in thinking outside the box
(that ctors are functions and constrained to function like arguments)

Suppose we allowed 'move' to be used with limited keyword status, i.e.
it only acts like a keyword in the context of the only parameter in a
ctor. I could then write:


class mytype {
public:
        mytype(move);
// everythting else
};

Now, inside the definition of mytype::mytype(move) make move refer to
the argument supplied by a move construction.

I hazard a guess that there is a miniscule amount of existing code that
has a type called move that could be broken by this extension.

Now how important is it that we should also provide move semantics for
assignment for classes that also need an ordinary copy assignment?

--
ACCU Spring Conference 2003 April 2-5
The Conference you should not have missed
ACCU Spring Conference 2004 Late April
Francis Glassborow      ACCU



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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: do-not-spam-benh@bwsint.com (Ben Hutchings)
Date: Wed, 23 Jul 2003 01:30:45 +0000 (UTC)
Raw View
In article <CvaF$kBST7G$Ewms@robinton.demon.co.uk>, Francis Glassborow wrote:
<snip>
> As I see it the major problem is the continued view of ctors as
> functions. Considering that they (officially) are nameless and certainly
> have no return values they clearly are unlike any other C++ entities.
> Even dtors can be called.

This is all very well, but I believe the move proponents want move
assignment operators as well.

<snip>
> Suppose we allowed 'move' to be used with limited keyword status, i.e.
> it only acts like a keyword in the context of the only parameter in a
> ctor.
<snip>

C++ has no unreserved keywords, and introducing one would make the
language yet more inconsistent.

How about declaring the move constructor as:

    class-name(~class-name parameter-name);
    class-name & operator=(~class-name parameter-name);

with the ~ hinting that the other instance is about to be destroyed?

---
[ 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, 23 Jul 2003 15:36:48 +0000 (UTC)
Raw View
> C++ has no unreserved keywords, and introducing one would make the
> language yet more inconsistent.
>
> How about declaring the move constructor as:
>
>     class-name(~class-name parameter-name);
>     class-name & operator=(~class-name parameter-name);
>
> with the ~ hinting that the other instance is about to be destroyed?

    Well, the problem is that other instance is not destroyed - just its
*content* *might* get "lost" - this is important difference.

    I think that in reality, move constructor should rather indicate
that other instance can be changed and that it can be a rvalue.
Personally (I will repeat myself before get noticed :) I think

    T(mutable T&);

    syntax describes this situation best - it indicates that the other
instance is about to be changed.

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: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Wed, 23 Jul 2003 15:37:06 +0000 (UTC)
Raw View
In article <slrnbhq849.18k.do-not-spam-benh@tin.bwsint.com>, Ben
Hutchings <do-not-spam-benh@bwsint.com> writes
>In article <CvaF$kBST7G$Ewms@robinton.demon.co.uk>, Francis Glassborow wrote:
><snip>
>> As I see it the major problem is the continued view of ctors as
>> functions. Considering that they (officially) are nameless and certainly
>> have no return values they clearly are unlike any other C++ entities.
>> Even dtors can be called.
>
>This is all very well, but I believe the move proponents want move
>assignment operators as well.

And operators already have some curious syntax to allow such things as
post increment and policy based allocation with operator new.

>
><snip>
>> Suppose we allowed 'move' to be used with limited keyword status, i.e.
>> it only acts like a keyword in the context of the only parameter in a
>> ctor.
><snip>
>
>C++ has no unreserved keywords, and introducing one would make the
>language yet more inconsistent.
It has stacks of them:-) they are all the entity names in the Standard
library.

So there is nothing to prevent us from creating another incomplete type
(along side void):

namespace std {
   class move;
}

and then allocating it some special semantic meaning.

>
>How about declaring the move constructor as:
>
>    class-name(~class-name parameter-name);
>    class-name & operator=(~class-name parameter-name);
>
>with the ~ hinting that the other instance is about to be destroyed?

Well let us throw that into the pot. I am convinced we need move
semantics and we need it in a way that is easy to explain and recognise.
If we are going to play tricks at least let us make them easy to
understand.



--
Francis Glassborow      ACCU
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ 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: Howard Hinnant <hinnant@metrowerks.com>
Date: Mon, 21 Jul 2003 03:09:40 GMT
Raw View
In article <86el0s759p.fsf@Zorthluthik.local.bar>, llewelly
<llewelly.at@xmission.dot.com> wrote:

| I have an odd question. Is:
|
| struct Bar
| {
|     Bar(Bar and); //Use alternative token
|     Bar(const Bar&);
| };
|
| well-formed under the move constructor proposal?

<chuckle>  You are right.  That *is* odd! :-)

Well, I pulled out my favorite compiler and did this:

struct Bar
{
   Bar(Bar bitand b);

   int data_;
};

Bar::Bar(Bar bitand b)
   : data_(b.data_)
{
}

int main()
{
}

and it compiled!  So I looked in the standard, 2.5/2 and it says:

| In all respects of the language, each alternative token behaves the
| same, respectively, as its primary token, except for its spelling

Hmmm... So I would have to say yes, "Bar and" is well formed under the
move proposal.  The rvalue reference is described in terms of the
reference.  It behaves like a reference except where the proposal says
it behaves differently.

--
Howard Hinnant
Metrowerks

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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: llewelly <llewelly.at@xmission.dot.com>
Date: Mon, 21 Jul 2003 06:19:00 GMT
Raw View
Howard Hinnant <hinnant@metrowerks.com> writes:

> In article <beks1o$6i1f7$1@ID-14036.news.uni-berlin.de>, Andrei
> Alexandrescu <SeeWebsiteForEmail@moderncppdesign.com> wrote:
>
> | void Foo(Bar);
> | void Foo(Bar&);
> | void Foo(const Bar&);
> |
> | would be distinct functions. The overloading rule would be that unnamed
> | temporaries go to the first overload.
> <snip>
> | This solution is backwards-compatible because it doesn't change the
> | semantics of existing correct programs; it just allows programs that were
> | incorrect and compile with a coherent semantics.
> |
> | The overloading rules would need to be changed to include the new rule. The
> | grammar and syntax need not be changed.
>
> <nod> This solution (or something close to it) has been fairly
> extensively discussed in subcommittee.
>
> One of the problems I see (and not everyone shares this view) is that
> this approach appears to allow moving from const rvalues.  I'm a little
> nervous about disregarding the const qualifier on an rvalue.
>
> And the "by value" copy constructor seems very unintuitive to me.  I'm
> having a heck of a time explaining:
>
> struct Bar
> {
>      Bar(Bar&&);
>      Bar(const Bar&);
> };

I have a suggestion, which I hope will help in explaining this
    feature:

    struct Bar
    {
        Bar(Bar __move);
        //...
    };

    with __move the syntactic replacement for '&&', in this
    context. I'm suggesting no change in semantics; just syntax, and
    just a simple replacement.

Here's what I think, even after having read your paper, and some other
    discussion on this topic, when I see Bar(Bar&&) :

    (a) Reference to reference. Not well-formed in C++, and as far as
        I can see, not remotely related to moving constructors.

    (b) Logical and. That's what && means currently. Obviously
        nonsensical here, but still no indicator of what it really
        does. (I mentioned the alternative token for '&&' in another
        post, but I don't think it's relevant here, so I'm just
        talking about the older '&&'.)

    (c) Typo - see (a).

    (d) Copy constructor. Before I used auto_ptr, I would have thought
        copy-constructor-like syntax for a move constructor would be
        okay, but after all the confusion I've seen caused by people
        confusing auto_ptr's transfer of ownership semantics with
        copying, I'm now convinced that the difference between move
        and copy is so important they shouldn't have remotely similar
        syntax, as that would make it much harder to teach people how
        different they are. Worse, the hordes of poorly qualifed C++
        instructors would automaticly assume a move constructor was
        'kind of like a copy constructor' and teach exactly the wrong
        thing.

I would like to see move constructors in C++200x, but With all these
    possibilities for confusion, I think if moving gets
    called '&&', a fair portion of those in need of it will never use it
    in their own classes, resulting in use below its
    potential. Further - you yourself say 'I'm having a heck of a time
    explaining ...' I can't help but get the impression you have
    trouble explaining this to other committee members. Ask yourself
    how much easier it would be to get the move constructor proposal
    accepted if more people understood it.

When I read your proposal, I couldn't help but think of the
    bit in D&E where Stroustrup mentions a scheme for exception syntax
    that used the keyword 'catch' in place 'try', 'throw' and of
    course 'catch' as well - a scheme he '... despaired of explaining
    ...' I fear bar(bar&&) is of similar nature.

C++ already has too much confusing syntax. Let's make sure new
    syntax doesn't fall in line behind the likes of foo()=0,
    operator++(int), and so forth.

(I don't mention Andrei's syntax, because, despite the fact that I
    admire him greatly, I consider his 'bar(bar)' to be even more
    confusing than 'bar(bar&&)' .)

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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: Howard Hinnant <hinnant@metrowerks.com>
Date: 12 Jul 2003 21:04:48 -0400
Raw View
In article <beks1o$6i1f7$1@ID-14036.news.uni-berlin.de>, Andrei
Alexandrescu <SeeWebsiteForEmail@moderncppdesign.com> wrote:

| void Foo(Bar);
| void Foo(Bar&);
| void Foo(const Bar&);
|
| would be distinct functions. The overloading rule would be that unnamed
| temporaries go to the first overload.
<snip>
| This solution is backwards-compatible because it doesn't change the
| semantics of existing correct programs; it just allows programs that were
| incorrect and compile with a coherent semantics.
|
| The overloading rules would need to be changed to include the new rule. The
| grammar and syntax need not be changed.

<nod> This solution (or something close to it) has been fairly
extensively discussed in subcommittee.

One of the problems I see (and not everyone shares this view) is that
this approach appears to allow moving from const rvalues.  I'm a little
nervous about disregarding the const qualifier on an rvalue.

And the "by value" copy constructor seems very unintuitive to me.  I'm
having a heck of a time explaining:

struct Bar
{
     Bar(Bar&&);
     Bar(const Bar&);
};

I cringe when I think about explaining:

struct Bar
{
     Bar(Bar);
     Bar(const Bar&);
};

But I admit it is a possibility.  Afterall, it is just syntax! :-)

These new overloading rules might break existing programs.  Consider
the following example (credit Peter Dimov):

template<class T> void f(T&); // #1

struct X {};
void f(X); // #2

int main()
{
    X x;
    f(x); // #2 now, #1 then?
}

If this last example truly can not be worked around, I consider that a
showstopper.

--
Howard Hinnant
Metrowerks
---
[ 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: "Ivan Vecerina" <ivecATmyrealboxDOTcom@swissonline.ch>
Date: Sun, 13 Jul 2003 15:57:44 GMT
Raw View
"Andrei Alexandrescu" <SeeWebsiteForEmail@moderncppdesign.com> wrote in
message news:beks1o$6i1f7$1@ID-14036.news.uni-berlin.de...
 > "Howard Hinnant" <hinnant@metrowerks.com> wrote in message
 > news:070720032058260726%hinnant@metrowerks.com...
 > > If you feel n1377.htm would benefit your code, please be vocal about it
 > > (please read it in detail first).  The committee is not likely to
 > > accept something this drastic unless it is convinced (by you) that it
 > > is really needed.

Count me among those who believe that an improvement is needed.
Personally I do like the n1377 proposal, and would fully support it.

 > My article () shows that the issue of unnecessary temporaries can be
solved
 > in many cases by just having functions take select arguments by value. To
 > distinguish between temporaries and nontemporaries inside a function, the
 > language change needed would be to allow values to overload with
references,
 > that is:
 >
 > // not C++
 > void Foo(Bar);
 > void Foo(Bar&);
 > void Foo(const Bar&);
 >
 > would be distinct functions. The overloading rule would be that unnamed
 > temporaries go to the first overload.

The problem I see with this is that the semantic of a function
such as:   void Foo(Bar);   would now suddenly be different
depending on the Bar type and the set of overloads provided.

Take for example:
    float sqr(float f);
    void Container::push_back( std::auto_ptr<T> p );

I would strongly prefer a different parameter type for the
second function, to make the takeover semantic obvious.

The && takeover reference looks good to me...


Anyway, I just hope for *some* solution to be provided in C++0x.
It is needed.


Kind regards,
--
  Ivan Vecerina, Dr. med.  <>  http://www.post1.com/~ivec
  Brainbench MVP for C++   <>  http://www.brainbench.com



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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: "Andrei Alexandrescu" <SeeWebsiteForEmail@moderncppdesign.com>
Date: Sun, 13 Jul 2003 15:58:01 GMT
Raw View
"Howard Hinnant" <hinnant@metrowerks.com> wrote in message
news:120720031035050576%hinnant@metrowerks.com...
 > In article <beks1o$6i1f7$1@ID-14036.news.uni-berlin.de>, Andrei
 > Alexandrescu <SeeWebsiteForEmail@moderncppdesign.com> wrote:
 >
 > | void Foo(Bar);
 > | void Foo(Bar&);
 > | void Foo(const Bar&);
 > |
 > | would be distinct functions. The overloading rule would be that unnamed
 > | temporaries go to the first overload.
 > <snip>
 > | This solution is backwards-compatible because it doesn't change the
 > | semantics of existing correct programs; it just allows programs that
were
 > | incorrect and compile with a coherent semantics.
 > |
 > | The overloading rules would need to be changed to include the new rule.
The
 > | grammar and syntax need not be changed.
 >
 > <nod> This solution (or something close to it) has been fairly
 > extensively discussed in subcommittee.
 >
 > One of the problems I see (and not everyone shares this view) is that
 > this approach appears to allow moving from const rvalues.  I'm a little
 > nervous about disregarding the const qualifier on an rvalue.

I was thinking, on the contrary, const rvalues are attracted by Foo(const
Bar&). If someone chose to return a const rvalue, they must've had their
reasons.

 > And the "by value" copy constructor seems very unintuitive to me.  I'm
 > having a heck of a time explaining:
 >
 > struct Bar
 > {
 >      Bar(Bar&&);
 >      Bar(const Bar&);
 > };

.. especially when && is overloaded :o).

 > I cringe when I think about explaining:
 >
 > struct Bar
 > {
 >      Bar(Bar);
 >      Bar(const Bar&);
 > };
 >
 > But I admit it is a possibility.  Afterall, it is just syntax! :-)

"Construct a Bar from a readily available Bar, existing as a temporary".

 > These new overloading rules might break existing programs.  Consider
 > the following example (credit Peter Dimov):
 >
 > template<class T> void f(T&); // #1
 >
 > struct X {};
 > void f(X); // #2
 >
 > int main()
 > {
 >     X x;
 >     f(x); // #2 now, #1 then?
 > }
 >
 > If this last example truly can not be worked around, I consider that a
 > showstopper.

I guess you're posting a slightly different example. The chosen fn would not
change at all in this example. The new rule only applies to the "trivial
conversions" stage, and that comes before templates are matched. Unless I'm
dead wrong, which is very possible :o).

Anyway, it's soothing to know that something simpler has been considered but
doesn't work for a reason that has been forgotten...


Andrei



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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: llewelly <llewelly.at@xmission.dot.com>
Date: 17 Jul 2003 03:49:32 -0400
Raw View
"Andrei Alexandrescu" <SeeWebsiteForEmail@moderncppdesign.com> writes:

> "Howard Hinnant" <hinnant@metrowerks.com> wrote in message
> news:120720031035050576%hinnant@metrowerks.com...
[snip]
>  > And the "by value" copy constructor seems very unintuitive to me.  I'm
>  > having a heck of a time explaining:
>  >
>  > struct Bar
>  > {
>  >      Bar(Bar&&);
>  >      Bar(const Bar&);
>  > };
>
> .. especially when && is overloaded :o).
[snip]

I have an odd question. Is:

struct Bar
{
    Bar(Bar and); //Use alternative token
    Bar(const Bar&);
};

well-formed under the move constructor proposal?
---
[ 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: pdimov@mmltd.net (Peter Dimov)
Date: 17 Jul 2003 03:50:03 -0400
Raw View
"Andrei Alexandrescu" <SeeWebsiteForEmail@moderncppdesign.com> wrote in message news:<beqc68$7u29c$1@ID-14036.news.uni-berlin.de>...
> "Howard Hinnant" <hinnant@metrowerks.com> wrote in message
> news:120720031035050576%hinnant@metrowerks.com...
>  > These new overloading rules might break existing programs.  Consider
>  > the following example (credit Peter Dimov):
>  >
>  > template<class T> void f(T&); // #1
>  >
>  > struct X {};
>  > void f(X); // #2
>  >
>  > int main()
>  > {
>  >     X x;
>  >     f(x); // #2 now, #1 then?
>  > }
>  >
>  > If this last example truly can not be worked around, I consider that a
>  > showstopper.
>
> I guess you're posting a slightly different example. The chosen fn would not
> change at all in this example. The new rule only applies to the "trivial
> conversions" stage, and that comes before templates are matched. Unless I'm
> dead wrong, which is very possible :o).

The two candidates are

void f<X>(X&);
void f(X);

In the current language they are equally viable, and the non-template
beats the template.

If the rules are altered to resolve the X& / X ambiguity, f(X&) would
beat f(X) at the overload resolution stage, before the
non-template/template tie breaker.

> Anyway, it's soothing to know that something simpler has been considered but
> doesn't work for a reason that has been forgotten...

There are other factors to consider. As presented, N1377 offers a
general way to bind a reference to a non-const rvalue. This can be
used not only for move, but for forwarding (N1385) and for declaring
non-members that can operate on a non-const rvalue (as currently
non-const members can.)
---
[ 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: David Abrahams <dave@boost-consulting.com>
Date: 17 Jul 2003 23:02:25 -0400
Raw View
"Andrei Alexandrescu" <SeeWebsiteForEmail@moderncppdesign.com> writes:

>  > These new overloading rules might break existing programs.  Consider
>  > the following example (credit Peter Dimov):
>  >
>  > template<class T> void f(T&); // #1
>  >
>  > struct X {};
>  > void f(X); // #2
>  >
>  > int main()
>  > {
>  >     X x;
>  >     f(x); // #2 now, #1 then?
>  > }
>  >
>  > If this last example truly can not be worked around, I consider that a
>  > showstopper.
>
> I guess you're posting a slightly different example. The chosen fn would not
> change at all in this example. The new rule only applies to the "trivial
> conversions" stage, and that comes before templates are matched. Unless I'm
> dead wrong, which is very possible :o).
>
> Anyway, it's soothing to know that something simpler has been considered but
> doesn't work for a reason that has been forgotten...

IIRC one of the reasons was that when you work out the use cases, it
is actually harder to define the move construct overload set because
you now need the T(T) and T(T&) constructors.  Howard, can you dig up
the details?

--
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: "Andrei Alexandrescu" <SeeWebsiteForEmail@moderncppdesign.com>
Date: Sat, 12 Jul 2003 08:01:56 GMT
Raw View
"Howard Hinnant" <hinnant@metrowerks.com> wrote in message
news:070720032058260726%hinnant@metrowerks.com...
 > If you feel n1377.htm would benefit your code, please be vocal about it
 > (please read it in detail first).  The committee is not likely to
 > accept something this drastic unless it is convinced (by you) that it
 > is really needed.

I had an idea (that you and I discussed in the past), which I believe is a
tad simpler than the existing proposal.

My article () shows that the issue of unnecessary temporaries can be solved
in many cases by just having functions take select arguments by value. To
distinguish between temporaries and nontemporaries inside a function, the
language change needed would be to allow values to overload with references,
that is:

// not C++
void Foo(Bar);
void Foo(Bar&);
void Foo(const Bar&);

would be distinct functions. The overloading rule would be that unnamed
temporaries go to the first overload.

This rule would apply to constructors, too, that is:

class Bar {
     void Bar(Bar);
     void Bar(Bar&);
     void Bar(const Bar&);
};

would be distinct constructors. The first overload takes an unnamed
temporary.

On the face of it, Bar(Bar) looks an impossibility. It's been explained
since the beginnings of C++ that the language couldn't allow a constructor
to take its rhs by value, because that would imply another constructor being
called to build that rhs, and so on ad infinitum.

That reasoning, however, can be challenged. If the object is already
available as an unnamed temporary, no extra constructor call is conceptually
needed so the loop is closed. There is no infinite recursion.

This language change allows a range of expressive new idioms. (I'm sure they
would be allowable with the existing proposal as well. I believe this change
does it with economy of means.) Here are some:

0. (Default use) Can create objects anyhow, temporaries are funneled to an
overloaded c'tor:

class Blah {
public:
     Blah(Blah);
     Blah(Blah&);
     Blah(const Blah&);
     ...
};

1. Can create objects, pass them to functions, return them from functions,
but not copy them to named objects. Perfect for auto_ptr!

class Blah {
     Blah();
public:
     Blah(Blah);
     static Blah Make(some_args);
     ...
};

2. Can create objects but only copy constant objects (good for some string
classes)

class Blah {
     Blah(Blah);
     Blah(Blah&);
public:
     Blah(const Blah&);
     ...
};

3. Can only create non-const objects for all practical purposes:

class Blah {
     Blah(const Blah&);
public:
     Blah(Blah&);
     Blah(Blah);
     ...
};

4. Cannot create unnamed temporary objects for any practical purposes.
Useful for locks or stuff like that.

class Blah {
     Blah(Blah);
public:
     Blah(const Blah&);
     Blah(Blah&);
     ...
};

This solution is backwards-compatible because it doesn't change the
semantics of existing correct programs; it just allows programs that were
incorrect and compile with a coherent semantics.

The overloading rules would need to be changed to include the new rule. The
grammar and syntax need not be changed.


Andrei



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

[ 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                       ]