V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
sbldehanhan
V2EX  ›  C++

这段代码有问题吗?

  •  
  •   sbldehanhan · 2023-10-12 17:07:58 +08:00 · 2447 次点击
    这是一个创建于 442 天前的主题,其中的信息可能已经有所发展或是发生改变。
    #include <iostream>
    #include <thread>
    #include <mutex>
    #include <condition_variable>
    #include <vector>
    
    class MyClass {
    public:
        MyClass(int num_conds) : conds_(num_conds), mutexes_(num_conds) {
        }
    
    private:
        std::vector<std::condition_variable> conds_;
        std::vector<std::mutex> mutexes_;
    };
    
    int main() {
        int num_conds = 5;
        MyClass my_class(num_conds);
    
        return 0;
    }
    

    我的目的是想在类初始化时根据传入的参数设置条件变量容器 cons_和互斥锁容器 mutexes_的大小,并向其中添加对应数量的元素。但是 c++的条件变量不支持拷贝复制,所以不能 push_back 。 这是 newbing 给的一段代码,能编译能跑,请问对吗?

    20 条回复    2023-10-13 13:33:09 +08:00
    crissx
        1
    crissx  
       2023-10-12 17:13:40 +08:00
    GPT4 这样说的:

    你的目标是在类初始化时根据传入的参数设置 conds_和 mutexes_的大小。目前的代码确实做到了这一点。

    但你提到了关于 std::condition_variable 不支持拷贝构造的问题,这确实是一个问题。然而,你的当前代码不会触发这个问题,因为你在初始化列表中使用了构造函数直接设置了其大小,而没有使用 push_back 。

    具体来说,这里:


    MyClass(int num_conds) : conds_(num_conds), mutexes_(num_conds) {
    }
    你用的是 std::vector 的"fill constructor",它会创建指定数量的默认初始化的元素。在这种情况下,不涉及拷贝或移动。

    总结,你的代码是可以编译和运行的,并且它按预期工作。不过,你确实要注意不要试图拷贝 std::condition_variable ,因为它确实不支持拷贝操作。如果需要移动这些对象,那么你可以考虑使用 std::vector<std::unique_ptr<std::condition_variable>>这样的结构,但在当前的代码和需求下,你不需要这么做。
    sheyueji
        2
    sheyueji  
       2023-10-12 17:29:32 +08:00
    push_back()除了支持拷贝构造外,还支持传递右值引用,就像楼上说的,你可以传递智能指针向 std::vector<std::unique_ptr<std::condition_variable>>中添加元素
    sbldehanhan
        3
    sbldehanhan  
    OP
       2023-10-12 17:31:33 +08:00
    @crissx #1 牛啊。说的好详细啊。
    sbldehanhan
        4
    sbldehanhan  
    OP
       2023-10-12 17:33:31 +08:00
    @sheyueji #2 那我也需要有条件变量的实例。我就是要在初始化时根据参数指定的数量创建条件变量的个数。
    cnbatch
        5
    cnbatch  
       2023-10-12 17:44:08 +08:00
    除了 push_back ,还有 emplace_back 吧
    如果以后需要动态添加的话,就 emplace_back
    sheyueji
        6
    sheyueji  
       2023-10-12 17:44:50 +08:00
    @sbldehanhan 没理解你什么意思,你在构造函数里创建对应数量的实例不就行了
    ysc3839
        7
    ysc3839  
       2023-10-12 17:55:38 +08:00 via Android
    看上去没问题,不支持拷贝的对象在 vector 中也可以构造时一次性初始化。
    sheyueji
        8
    sheyueji  
       2023-10-12 18:04:46 +08:00
    @sbldehanhan 好像是我想歪了,构造确实没问题,就是没办法再加数据了而已
    cnbatch
        9
    cnbatch  
       2023-10-12 23:08:39 +08:00
    @cnbatch 想起来了,不能 emplace_back ,不能直接追加。
    我以前遇到过类似的,std::vector<std::atomic<T>>,一样的情况。
    最后两个解决办法,第一个就是像这里提到的加一层智能指针,第二个办法比较特殊——std::map 的第二个值,不用 insert(),而是中括号直接插入。

    还有我自己使用过的、改造过的第三方库就有这样的用法,构造时直接初始化。太久没碰都差不多忘了有这回事。
    hitmanx
        10
    hitmanx  
       2023-10-12 23:16:19 +08:00
    一般像 condition_variable 之类的,如果一定要放在 vector 里的话,用 std::unique_ptr 包一层是更好的,也更常见。
    优点一是 condition_variable 本身是不支持移动的,所以你的 vector 是没法 grow 的。且用 unique_ptr 包一层,无论是将来移除个别元素还是替换都会更灵活一些。

    用裸的 std::vector<std::condition_variable>主要是可以利用内存的局部性原理,因为所有的元素是放在一个 array 里的。另外相比用 unique_ptr 包一层,也可以减少一些 heap 碎片。但是在这里,似乎灵活性比这两点会更重要一些。
    hitmanx
        11
    hitmanx  
       2023-10-12 23:22:37 +08:00
    @cnbatch 应该不能 emplace_back 。condition_variable 是不支持 copy 且不支持 move 的。
    emplace_back 会增加 vector 的 size ,所以是有可能触发 vector 的 grow 的,但是如果里面的元素不支持 move ,它是没有办法完成 grow 的。
    cnbatch
        12
    cnbatch  
       2023-10-12 23:46:43 +08:00
    @hitmanx 没错,不能 emplace_back 。
    以前我就弄过同样的代码,长时间没碰都快忘了
    dangyuluo
        13
    dangyuluo  
       2023-10-13 04:34:05 +08:00
    代码能编译但是不代表是对的,对与错还是要看你的目的是什么。至于 condition_variable 为什么不能 copy 和 move ,需要从多线程安全和操作系统原理理解了
    yolee599
        14
    yolee599  
       2023-10-13 08:20:19 +08:00 via Android
    @crissx #1 发 AI 生成的内容会被站长 ban ,这是个技术问题,请问你验证过内容正确性吗?
    sbldehanhan
        15
    sbldehanhan  
    OP
       2023-10-13 09:30:01 +08:00
    @cnbatch #5 无论怎么 back ,调用的都是拷贝构造函数。条件变量把拷贝构造函数删了,也就是不允许复制。
    sbldehanhan
        16
    sbldehanhan  
    OP
       2023-10-13 09:33:07 +08:00
    @cnbatch #9 那你的 vector 里面的元素数量是写死的?还是在初始化时可以根据参数设置?
    sbldehanhan
        17
    sbldehanhan  
    OP
       2023-10-13 09:35:19 +08:00
    @hitmanx #10 但是我需要多个条件变量,数量也不想写死。而是能在类实例化时用参数指定。
    hitmanx
        18
    hitmanx  
       2023-10-13 10:58:37 +08:00
    @sbldehanhan 我回复里不是写了嘛?如果数量不确定,要支持动态的 grow ,用 std::vector<std::unique_ptr<std::condition_variable>>
    sbldehanhan
        19
    sbldehanhan  
    OP
       2023-10-13 11:18:39 +08:00
    @hitmanx #18 我的意思是根据参数创建对应个数的条件变量的实例。vector 里的指针不是指向一个条件变量,而是指向参数个条件变量。
    cnbatch
        20
    cnbatch  
       2023-10-13 13:33:09 +08:00
    @sbldehanhan
    我的办法是,std::unique_ptr<std::condition_variable[]>
    这样在构造函数可以手动初始化,std::make_unique<std::condition_variable[]>(想要设置的数量)

    https://github.com/cnbatch/kcptube/blob/main/src/3rd_party/thread_pool.hpp
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2805 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 02:26 · PVG 10:26 · LAX 18:26 · JFK 21:26
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.