为什么既没有使用clang声明也没有删除移动构造函数?

 静默的温柔结成思念 发布于 2023-02-10 11:05

考虑以下类.

struct with_copy {
    with_copy() = default;
    with_copy(with_copy const&) {}
    with_copy& operator=(with_copy const&) { return *this; }
};

struct foo {
    with_copy c;
    std::unique_ptr p;
};

是否with_copy有一个拷贝构造函数?是.它是明确定义的.

是否with_copy有一个移动构造函数?不可以.显式复制构造函数阻止生成它.

是否with_copy有删除的移动构造函数?不.没有移动构造函数与删除构造函数不同.删除的移动构造函数会尝试将格式错误而不是退化移动到副本.

with_copy复制吗?是.其复制构造函数用于复制.

with_copy可移动的?是.它的复制构造函数用于移动.

......现在是棘手的.

是否foo有一个拷贝构造函数?是.它有一个删除的,因为它的默认定义将由于调用unique_ptr已删除的复制构造函数而格式不正确.

是否foo有一个移动构造函数?GCC说是的,clang说没有.

是否foo有删除的移动构造函数?海湾合作委员会和铿锵声说不.

foo复制吗?不会.它的复制构造函数被删除.

foo可移动的?GCC说是的,clang说没有.

(当考虑赋值而不是构造时,行为类似.)

据我所知,海湾合作委员会是正确的.foo应该有一个移动构造函数,在每个成员上执行移动,在这种with_copy情况下退化为副本.Clang的行为似乎很荒谬:我有一个有两个可移动成员的聚合体,但我的聚合物是一个不可移动的砖块.

谁是对的?

2 个回答
  • 我不太确定你测试的foo是什么,但它肯定都是可移动的,可移动的.不可否认,这并没有说明移动构造函数或移动赋值是否可访问,只是来自右值的构造或赋值有效.这两个铛(铛版本3.5(主干196718))和海湾合作委员会(GCC版本4.9.0 20131031(实验)(GCC))同意这样的评价.这是我尝试的完整来源:

    #include <iostream>
    #include <type_traits>
    #include <memory>
    
    struct with_copy {
        with_copy() = default;
        with_copy(with_copy const&) {}
        with_copy& operator=(with_copy const&) { return *this; }
    };
    
    struct foo {
        with_copy c;
        std::unique_ptr<int> p;
    };
    
    int main()
    {
        std::cout << "move constructible: "
                  << std::is_move_constructible<foo>::value << '\n';
        std::cout << "move assignable: "
                  << std::is_move_assignable<foo>::value << '\n';
        foo f0;
        foo f1 = std::move(f0);
        f0 = std::move(f1);
    }
    

    2023-02-10 11:07 回答
  • C++ 11,或者更确切地说是n3485,[class.copy]/9:

    如果类的定义X没有显式声明一个移动构造函数,那么当且仅当一个类的定义被隐式声明为默认值时

    X 没有用户声明的复制构造函数,

    X 没有用户声明的复制赋值运算符,

    X 没有用户声明的移动赋值运算符,

    X 没有用户声明的析构函数,和

    移动构造函数不会被隐式定义为已删除.

    和/ 11:

    隐式声明的复制/移动构造函数是inline public其类的成员.X如果X具有以下内容,则将类的默认复制/移动构造函数定义为已删除(8.4.3):

    [...]

    对于复制构造函数,rvalue引用类型的非静态数据成员,或

    对于移动构造函数,一个非静态数据成员或直接或虚拟基类,其类型没有移动构造函数,并且不是简单的可复制.

    由于with_copy平凡的拷贝,但foo动器构造器(它会被定义为删除,因此它不会被隐式声明).


    C++ 1y,或者更确切地说是2013年12月12日的github repo commit e31867c0; 合并DR1402:

    / 9:

    如果类的定义X没有显式声明一个移动构造函数,那么当且仅当一个类的定义被隐式声明为默认值时

    X 没有用户声明的复制构造函数,

    X 没有用户声明的复制赋值运算符,

    X 没有用户声明的移动赋值运算符,和

    X 没有用户声明的析构函数.

    和/ 11:

    隐式声明的复制/移动构造函数是inline public 其类的成员.X 如果X具有以下内容,则将类的默认复制/移动构造函数定义为已删除(8.4.3):

    [...]

    对于复制构造函数,rvalue引用类型的非静态数据成员.

    超载解析(13.3,13.4)忽略定义为已删除的默认移动构造函数.

    这里foo将有一个move-constructor.

    2023-02-10 11:07 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有