这段代码有问题吗? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
sbldehanhan
V2EX    C++

这段代码有问题吗?

  •  
  •   sbldehanhan 2023-10-12 17:07:58 +08:00 2833 次点击
    这是一个创建于 728 天前的主题,其中的信息可能已经有所发展或是发生改变。
    #include <iostream> #include <thread> #include <mutex> #include <condition_variable> #include <vector> clss 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     Solana     855 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 21:40 PVG 05:40 LAX 14:40 JFK 17:40
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86