Bug 64092 - when explicit using synthesized move operation (constructor and assignment operator), synthesize move constructor by calling member's copy constructor
Summary: when explicit using synthesized move operation (constructor and assignment op...
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.9.3
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-11-27 10:18 UTC by xbguo
Modified: 2014-11-28 09:01 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description xbguo 2014-11-27 10:18:30 UTC
(1) g++ -v output info:

Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/home/hillstone/libexec/gcc/i686-pc-linux-gnu/4.9.3/lto-wrapper
Target: i686-pc-linux-gnu
Configured with: ../gcc_4.9/configure --with-pkgversion='gxb'\''s c++ study' --prefix=/home/hillstone
Thread model: posix
gcc version 4.9.3 20141124 (prerelease) (gxb's c++ study)

i build gcc by myself, Before and after gcc4.9.2 released,it has the same problem。

(2) svn info output info:

Path: .
URL: svn://gcc.gnu.org/svn/gcc/branches/gcc-4_9-branch
Repository Root: svn://gcc.gnu.org/svn/gcc
Repository UUID: 138bc75d-0d04-0410-961f-82ee72b054a4
Revision: 217996
Node Kind: directory
Schedule: normal
Last Changed Author: gccadmin
Last Changed Rev: 217994
Last Changed Date: 2014-11-24 08:16:23 +0800 (Mon, 24 Nov 2014)

(3)test code

#include <iostream>
#include <utility>
class foo{
    public:
        foo() = default;

        foo(const foo &fv):iv(fv.iv){std::cout << "foo copy constructor\n";}
        foo &operator=(foo &fv)
        {
            std::cout << "foo copy assignment\n";
            iv = fv.iv;
            return *this;
        }
        ~foo()
        {
            std::cout << "foo destructor\n";
        }
    private:
        int iv;
};

class test
{
    public:
        test() = default;
        test(const test &tv):iv(tv.iv){
            std::cout << "test copy constructor\n";
        }

        test &operator=(const test &fv)
        {
            std::cout << "test copy assignment\n"; 
            iv = fv.iv;
            return *this;
        }
        test(test &&) = default;
        test &operator=(test &&) = default;
    private:
        int iv;
        foo fv;
};

int main()
{
    test ta;
    test tb(std::move(ta));
    ta = std::move(tb);
    return 0;
}

(4)compiling cmmand

 g++ -std=c++11 test_move_operation_match.cpp -o test

(5)test program output

./test 
foo copy constructor
test copy assignment
foo destructor
foo destructor

(6)result analysis

in class test,we explicit use synthesized move operation,and define copy operation with output information。Had class test have a data member with foo class type。we make class foo have copy constructor、copy assignment operator and destructor。

there was no “test copy constructor” outputs but ”foo copy constructor“,
this means that the compiler chooses the the synthesized move constructor which 
calls the member‘s copy constructor。Is this OK? 

in the ”c++ primer 5th“ 13.6.2 chapter,the class test’s move constructor should be ”delete“。similarly for move assignment operator。

Another output ”test copy assignment“,compiler uses copy assignment operator。

what about the move assignment operator? isn't synthesizeed at all or synthesized as ”delete“。

i think both the two move operations shuld be ”delete“。“=default” indicate the compiler synthesizes move operation。when compiler can't achieve,it should nofity the user by declaring “delete”。i agree with ”c++ primer“ book。


my english so poor,i may not describe the problem clearly and may have improper tone。Don't keep that in mind。
Comment 1 Daniel Krügler 2014-11-27 22:51:01 UTC
(In reply to xbguo from comment #0)
> in class test,we explicit use synthesized move operation,and define copy
> operation with output information。Had class test have a data member with foo
> class type。we make class foo have copy constructor、copy assignment operator
> and destructor。
> 
> there was no “test copy constructor” outputs but ”foo copy constructor“,
> this means that the compiler chooses the the synthesized move constructor
> which calls the member‘s copy constructor。Is this OK? 

The compiler behaviour looks correct to me. Let me start by pointing out that the observed behaviour is affected by a very recent core resolution of

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1402

> in the ”c++ primer 5th“ 13.6.2 chapter,the class test’s move constructor
> should be ”delete“。similarly for move assignment operator。

No, it is not deleted, but there is simple no move constructor declared nor a move assignment operator (Even if it *were* deleted - but not in this example -  that would just mean that these functions would be ignored during overload resolution). The move constructor of foo exist, but it just calls the base class copy constructor (selected by overload resolution), because there are no base class move constructor available.
 
> Another output ”test copy assignment“,compiler uses copy assignment operator。
>
> what about the move assignment operator? isn't synthesizeed at all or
> synthesized as ”delete“。

The difference here is as follows: Again, the base class has no move constructor. But in this case the derived class also has no move assignment operator, because the base class has no copy constructor to which an rvalue could be provided as argument (since the existing copy constructor has a non-const argument). The effect is that overload resolution now cannot select

test &operator=(test &&)

but still finds the remaining (and matching) copy constructor

test &operator=(const test &fv)

> i think both the two move operations shuld be ”delete“。“=default” indicate
> the compiler synthesizes move operation。when compiler can't achieve,it
> should nofity the user by declaring “delete”。i agree with ”c++ primer“ book。

No, the language change has been performed intentionally to allow that copying still can happen, if a move cannot be performed.
 
Albeit I think that the standard is clear what should happen here (and existing compilers seem to implement that correctly), I do have the feeling that the standard is currently unclear what the actual state of 

test &operator=(test &&) = default;

is. The wording doesn't really say that it is deleted, nor does it say that it does not exist, because I cannot find the current situation exactly described. None of the cases enumerated in p23 b4 is valid here. What happens here is that overload resolution simply does not *succeed*. What the wording says it that the move assignment operator of test is not odr-used and therefore not defined, because overload resolution is not successful.
Comment 2 xbguo 2014-11-28 05:12:15 UTC
Thank you very much for your patient explanation, thanks again.