可以复制C ++ 20协程吗? [英] Can C++20 coroutines be copied?

查看:74
本文介绍了可以复制C ++ 20协程吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在研究C ++ 20协程,并试图将我的一些代码库移到使用它们.不过,我遇到了一个问题,因为似乎无法复制新的协程. generator 对象已删除了复制构造函数和复制分配运算符,而我所研究的似乎没有办法.

I've been playing around with C++20 coroutines and trying to move some of my codebase over to use them. I've run into an issue, though, as it doesn't seem that the new coroutines can be copied. The generator objects have deleted copy-constructors and copy-assignment operators, and nothing I've looked into has seemed to have a way.

可以做到吗?

作为参考,我编写了一个小测试程序,尝试复制C ++ 20协程失败,并且成功尝试使用 boost :: asio :: coroutine 做同样的事情.这使用的是Visual Studio 2019版本16.3.7

For reference, I have written a little test program with a failing attempt at copying C++20 coroutines as well as a successful attempt to do the same thing with boost::asio::coroutine. This is using Visual Studio 2019 version 16.3.7

#include <sdkddkver.h>
#include <string>
#include <algorithm>
#include <iterator>
#include <experimental\resumable>
#include <experimental\generator>
#include <cassert>

#include <boost\asio\yield.hpp>

namespace std_coroutines {
    auto letters() {
        for (auto c = 'a'; ; ++c)
            co_yield c;
    }

    void run() {
        auto gen = letters();
        std::string s1, s2;
        std::copy_n(gen.begin(), 3, std::back_inserter(s1)); // append "abc" to s1
        //auto gen_copy = gen; // doesn't compile

        std::copy_n(gen.begin(), 3, std::back_inserter(s1)); // append "def" to s1
        //std::copy_n(gen_copy.begin(), 3, std::back_inserter(s2)); // append "def" to s2

        assert(s1 == "abcdef");
        assert(s2 == "def"); // fails
    }
};// namespace std_coroutines

namespace boost_asio_coroutines {
    struct letters : boost::asio::coroutine {
        char c = 'a';
        char operator()() {
            reenter(this) for (;; ++c)
            {
                yield return c;
            }
        }
    };

    void run() {
        auto gen = letters();
        std::string s1, s2;
        std::generate_n(std::back_inserter(s1), 3, std::ref(gen)); // append "abc" to s1
        auto gen_copy = gen;
        std::generate_n(std::back_inserter(s1), 3, std::ref(gen)); // append "def" to s1
        std::generate_n(std::back_inserter(s2), 3, std::ref(gen_copy)); // append "def" to s2

        assert(s1 == "abcdef");
        assert(s2 == "def");
    }
} // namespace boost_asio_coroutines

int main() {
    boost_asio_coroutines::run();
    std_coroutines::run();
}

推荐答案

TS不会明确阻止复制.正如您提到的, std :: experimental :: generator 承诺对象已删除复制操作.我认为,最初的实现对于副本还是比较保守的,因为有很多需要考虑的地方.

The TS doesn't explicitly prevent copies. As you mentioned, std::experimental::generator promise object has deleted copy operations. I think that initial implementations are being conservative about copies because there is a lot to consider.

协程管理协程激活上下文的句柄,由协程状态/papers/2018/n4775.pdf"rel =" nofollow noreferrer> N4775 .此状态是在堆还是堆栈上(出于优化原因)是实现定义的.协程存储本身的格式也是实现定义的.

Coroutines manage a handle to the coroutine's activation context, formally called the coroutine state by N4775. Whether this state is on the heap or the stack (for optimization reasons), is implementation-defined. The format of the coroutine-storage itself is also implementation-defined.

只要沿 shared_ptr weak_ptr 的路线建立了协程句柄的所有权语义,该实现就可以实现浅表复制(类推位,因为只有一个协程是国家的实际所有者,而所有其他协程员都是观察员).

A shallow copy could be accomplished by the implementation so long as ownership semantics of the coroutine handle were established along the lines of shared_ptr and weak_ptr (the analogy falls apart a bit because only one coroutine is the actual owner of the state, while all others are observers).

如果您要问的是深拷贝,那么您最终会得到两个互不影响的独立生成器,那么我想所有的含义也是有可能的.

If you're asking about deep copies, where you end up with two separate generators that do not influence each other, I suppose it would be possible, too, with all the implications.

我能想到的一些含义:

  • 深度复制函数的局部变量非常昂贵,而这种额外的分配开销可能会让用户感到意外.
  • 复制的协程句柄将始终*需要驻留在堆上,这意味着您可能最终会遇到原始"协程具有良好性能而复制的协程具有较差性能的情况.偶然的副本可能会悄无声息地终止优化.

* 协程存储是通过调用全局非数组 new 函数获得的.从理论上讲,您可以重载此函数以匹配协程,但是由于存储是实现定义的,因此您必须了解您的平台.尽管如此,从理论上讲,这仍将允许您使用保留了堆栈大部分的全局竞技场分配器,例如

*Storage for coroutines is obtained by calling a global non-array new function. You could theoretically overload this function to match your coroutine, but since the storage is implementation-defined, you'd have to know your platform. Still, this would allow you to theoretically utilize a global arena allocator that has reserved a chunk of the stack, for example

这篇关于可以复制C ++ 20协程吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆