保证复制省略和不可移动Nonmoveable

Posted

技术标签:

【中文标题】保证复制省略和不可移动Nonmoveable【英文标题】:Guaranteed copy elision and NonmoveableNonmoveable保证复制省略和不可移动Nonmoveable 【发布时间】:2016-10-07 15:32:24 【问题描述】:

我发现 GCC 7 已经实现了保证复制省略,我在wandbox 中尝试了以下代码:

#include <iostream>

struct NonMovable

    NonMovable() noexcept = default;
    NonMovable(NonMovable&&) noexcept = delete;
    NonMovable& operator=(NonMovable&&) noexcept = delete;
;

NonMovable Make()

    return ;



int main()

    //[[maybe_unused]] const auto x = Make();
    //const auto z = NonMovable;
    [[maybe_unused]] const auto y = NonMovableNonMovable;

我得到了编译错误:

prog.cc: In function 'int main()':
prog.cc:20:60: error: use of deleted function 'NonMovable::NonMovable(NonMovable&&)'
     [[maybe_unused]] const auto y = NonMovableNonMovable;
                                                            ^
prog.cc:6:5: note: declared here
     NonMovable(NonMovable&&) noexcept = delete;
     ^~~~~~~~~~

根据cppreference:

在初始化时,如果初始化表达式是纯右值并且 源类型的 cv 非限定版本与 目标的类,初始化表达式用于 初始化目标对象:T x = T(T(T())); // only one call to default constructor of T, to initialize x

所以我认为它应该等于const Movable y;。怎么了?

【问题讨论】:

看来是GCC的bug。该代码在新版本的 GCC 上编译良好。 【参考方案1】:

列表初始化无法让您精确控制发生的情况。基本上委员会已经猜到了程序员最可能想做什么,并赋予了相应的含义。

如果您想进行精确控制,请使用非列表初始化。为此,您的测试用例应该可以正常工作。

如果你坚持列表初始化,那么对于聚合,我认为当前的措辞可以做到这一点并应用保证副本“省略”,因为他们说

如果 T 是一个聚合类并且初始化器列表有一个类型为 cv U 的元素,其中 U 是 T 或从 T 派生的类,则从该元素初始化对象(通过复制初始化复制列表-初始化,或通过直接初始化直接列表初始化)。

此外,您可能在标准的未来修订版或缺陷报告解决方案中获得您想要的东西,即使是非聚合。我相信你的类是一个聚合,所以它应该编译。但也许我在这里缺少一些东西。

【讨论】:

" 使用非列表初始化。" 会是 const auto y = NonMovable(NonMovable()); 吗?如果是这样,那似乎也不起作用。

以上是关于保证复制省略和不可移动Nonmoveable的主要内容,如果未能解决你的问题,请参考以下文章

为啥 c++ 线程是可移动的但不可复制的?

Initializer-list-构造一个不可复制(但可移动)对象的向量

使类不可复制*和*不可移动

如果 lambda 使用 std::move() 捕获不可复制的对象,为啥它是不可移动的?

不使用聚合初始化直接初始化不可复制、不可移动的成员

为啥 C++11 不能将不可复制的仿函数移动到 std::function?