jac*_*bsa 8 c++ copy-elision c++17 c++20
在 C++17 及更高版本中,有保证的复制省略意味着可以从一系列函数返回不可移动的对象,一直到最终调用者:
struct NonMoveable {
NonMoveable() = default;
NonMoveable(NonMoveable&&) = delete;
};
NonMoveable Foo() { return NonMoveable(); }
NonMoveable Bar() { return Foo(); }
NonMoveable Baz() { return Bar(); }
NonMoveable non_moveable = Baz();
Run Code Online (Sandbox Code Playgroud)
是否有一些技巧可以禁用特定类型的保证复制省略,以便不可能编写类似Bar及Baz以上的函数来传递NonMoveable从另一个函数获得的对象?(我不知道是否Foo应该被禁止。)
我知道这是一个奇怪的要求。如果您对我想做的事情感兴趣:我正在开发一个协程库,其中的约定是,如果您Task从函数返回 a,则该函数的所有引用参数都需要保持有效,直到任务已准备就绪,即直到co_await任务的表达式求值为止。如果从另一个协程调用一个协程,这一切都完全可以正常工作,因为我已经安排该Task类型不可移动并按值接受:除了立即使用它以及您提供的任何临时对象之外,您无法对它执行任何操作co_await对子协程的调用将一直存在,直到co_await表达式求值为止。
除了你还可以用 做另一件事Task:编写像Bar上面Baz这样的函数return Foo()来代替co_return co_await Foo()。如果存在争议,Foo这可能是暂时的,在这种情况下,这样做是安全的,co_return co_await Foo(...)但不是return Foo(...)。
这可能会变得令人惊讶地微妙。例如,astd::function<Task(SomeObj)>内部包含一条return语句,并且很乐意绑定到接受 的 lambda const SomeObj&。当它被调用时,它将向 lambda 提供对其按值参数的引用,该引用会在 lambda 挂起时被销毁。
我正在寻找一种更优雅的方法来防止此问题,但与此同时,我想让有问题的表单不编译(这也有助于识别用户代码中的问题集)。我预计这是不可能的,但也许有一些我没有想到的技巧。