【问题标题】:Copy/move elision with a check用检查复制/移动省略
【发布时间】:2020-10-01 17:04:12
【问题描述】:

考虑this。有一个不可复制、不可移动的类,并且为它定义了一些谓词:

struct AA
{
    AA(AA const&  otehr) = delete;
    AA(AA      && otehr) = delete;
    AA& operator = (AA const&  otehr) = delete;
    AA& operator = (AA      && otehr) = delete;

    AA(int something) { }

    bool good() const { return false; }
};

由于在 C++17 中保证 copy/move-elision,我们可以拥有:

auto getA() { return AA(10); }

问题是:如何定义getGoodA,如果它返回good,它将转发getA,否则会抛出异常?有可能吗?

auto getGoodA()
{
    auto got = getA();
    if (got.good()) return got; // FAILS! Move is needed.
    throw std::runtime_error("BAD");
}

【问题讨论】:

  • 如果您反转支票会发生什么? if (!got.good()) throw std::runtime_error("BAD"); return got; ?
  • 其实没什么。仍然需要移动构造函数。
  • @Vahagn 希望这个问题在 C++23 中会消失:wg21.link/p2025

标签: c++ c++17 copy-elision noncopyable


【解决方案1】:

如果我们在 C++20 中进行了合同检查,您将能够编写如下内容:

auto getGoodA(int i) [[post aa: aa.good()]] {
    return getA(i);
}

(至少我是这么认为的——我对aa 返回伪变量的类型并不完全清楚;它需要是对其返回位置中返回对象的引用。)不幸的是,合同是@ 987654321@ 所以我们还需要一段时间才能写这篇文章。

假设您不能修改getA,目前唯一的方法是从getGoodA 返回一个包装类。显而易见的解决方案是unique_ptr,但我们实际上并不需要执行堆分配;延迟构造的包装器将 do just as well:

#include <cstddef>
#include <new>
struct BB {
    alignas(AA) std::byte buf[sizeof(AA)];
    template<class F, class G> BB(F f, G g) { g(*new (buf) AA{f()}); }
    BB(BB&&) = delete;
    ~BB() { reinterpret_cast<AA&>(buf).~AA(); }
    operator AA&() { return reinterpret_cast<AA&>(buf); }
    operator AA const&() const { return reinterpret_cast<AA const&>(buf); }
};
auto getGoodA(int i) {
    return BB{
        [&] { return getA(i); },
        [&](AA& aa) { if (!aa.good()) throw (struct bad**){}; }};
}

这里我给BB一个引用样式的接口,允许你写AA&amp; aa = getGoodA(i),但你同样可以给它一个指针样式的接口(@98​​7654331@和operator-&gt;),甚至复制接口AA.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-03
    • 1970-01-01
    • 2018-09-17
    • 2014-01-02
    • 2021-02-08
    • 1970-01-01
    • 2018-12-15
    相关资源
    最近更新 更多