如果结构包含互斥量,则C ++将初始化程序列表推入标准向量的问题

我目前正在C ++中的一个项目中,其中有一个存储在向量中的结构体列表,这些结构体与它们有很多关联。为了加快处理速度,我选择将程序拆分到多个线程中,而我选择这样做的惰性方法是在标准库向量的每个结构上添加互斥量。这样,我可以让多个线程在数组上进行迭代,并通过调用mutex.try_lock()并完成与该元素的关联处理,或移至下一个打开的元素,从而基本上获取各个元素的所有权。

在开始之前,请注意以下实际上是有效的。

#include <mutex>
#include <vector>

struct foo {
    int a;
    std::mutex b;
};

void working_demo () {
    // assign by initializer list
    foo f = {.a = 1};
}

int main () {
    working_demo();
}

因此,我打算以与上面非常相似的方式填充我的标准向量,并且不起作用。

#include <mutex>
#include <vector>

struct foo {
    int a;
    std::mutex b;
};

void broken_demo () {
    std::vector<foo> bar;

    // assign by initializer list
    bar.push_back({.a = 1});
}

int main () {
    broken_demo();
}

编译器错误:

clang++ -std=c++11 -Wall -Wextra -Wfatal-errors -pedantic -I./  -c -o demo.o demo.cpp
demo.cpp:13:20: warning: designated initializers are a C99 feature [-Wc99-extensions]
    bar.push_back({.a = 1});
                   ^~~~~~
In file included from demo.cpp:1:
In file included from /usr/sup/bin/../lib/gcc/x86_64-pc-linux-gnu/9.1.0/../../../../include/c++/9.1.0/mutex:38:
In file included from /usr/sup/bin/../lib/gcc/x86_64-pc-linux-gnu/9.1.0/../../../../include/c++/9.1.0/tuple:39:
In file included from /usr/sup/bin/../lib/gcc/x86_64-pc-linux-gnu/9.1.0/../../../../include/c++/9.1.0/array:39:
In file included from /usr/sup/bin/../lib/gcc/x86_64-pc-linux-gnu/9.1.0/../../../../include/c++/9.1.0/stdexcept:39:
In file included from /usr/sup/bin/../lib/gcc/x86_64-pc-linux-gnu/9.1.0/../../../../include/c++/9.1.0/string:41:
In file included from /usr/sup/bin/../lib/gcc/x86_64-pc-linux-gnu/9.1.0/../../../../include/c++/9.1.0/bits/allocator.h:46:
In file included from /usr/sup/bin/../lib/gcc/x86_64-pc-linux-gnu/9.1.0/../../../../include/c++/9.1.0/x86_64-pc-linux-gnu/bits/c++allocator.h:33:
/usr/sup/bin/../lib/gcc/x86_64-pc-linux-gnu/9.1.0/../../../../include/c++/9.1.0/ext/new_allocator.h:146:8: fatal error: call to implicitly-deleted copy constructor of 'foo'
                            _Up(std::forward<_Args>(__args)...)))
                            ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/sup/bin/../lib/gcc/x86_64-pc-linux-gnu/9.1.0/../../../../include/c++/9.1.0/bits/alloc_traits.h:483:24: note: in instantiation of exception specification for
      'construct<foo,foo>' requested here
        noexcept(noexcept(__a.construct(__p,std::forward<_Args>(__args)...)))
                              ^
/usr/sup/bin/../lib/gcc/x86_64-pc-linux-gnu/9.1.0/../../../../include/c++/9.1.0/bits/vector.tcc:115:21: note: in instantiation of exception specification for 'construct<foo,foo>'
      requested here
            _Alloc_traits::construct(this->_M_impl,this->_M_impl._M_finish,^
/usr/sup/bin/../lib/gcc/x86_64-pc-linux-gnu/9.1.0/../../../../include/c++/9.1.0/bits/stl_vector.h:1201:9: note: in instantiation of function template specialization
      'std::vector<foo,std::allocator<foo> >::emplace_back<foo>' requested here
      { emplace_back(std::move(__x)); }
        ^
demo.cpp:13:9: note: in instantiation of member function 'std::vector<foo,std::allocator<foo> >::push_back' requested here
    bar.push_back({.a = 1});
        ^
demo.cpp:6:16: note: copy constructor of 'foo' is implicitly deleted because field 'b' has a deleted copy constructor
    std::mutex b;
               ^
/usr/sup/bin/../lib/gcc/x86_64-pc-linux-gnu/9.1.0/../../../../include/c++/9.1.0/bits/std_mutex.h:94:5: note: 'mutex' has been explicitly marked deleted here
    mutex(const mutex&) = delete;
    ^

我可以肯定地说这是行不通的,原因是该结构正在尝试为互斥量调用复制构造函数,而互斥量实际上没有复制构造函数。我明确地不想这样做。

我最初的想法是,为了确保它甚至不尝试调用互斥量的副本构造函数,我可以为我的类创建自己的构造函数,并且基本上显式地省略了互斥量的复制。这种方法看起来像这样-但是它也不起作用。

#include <mutex>
#include <vector>

struct foo {
    foo (int A): a(A) {;}

    int a;
    std::mutex b;
};

void broken_demo () {
    std::vector<foo> bar;

    // assign by initializer list
    bar.emplace_back(1);
}

int main () {
    broken_demo();
}

编译器错误:

clang++ -std=c++11 -Wall -Wextra -Wfatal-errors -pedantic -I./  -c -o demo.o demo.cpp
In file included from demo.cpp:2:
In file included from /usr/sup/bin/../lib/gcc/x86_64-pc-linux-gnu/9.1.0/../../../../include/c++/9.1.0/vector:65:
/usr/sup/bin/../lib/gcc/x86_64-pc-linux-gnu/9.1.0/../../../../include/c++/9.1.0/bits/stl_construct.h:75:38: fatal error: call to implicitly-deleted copy constructor of 'foo'
    { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
                                     ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/sup/bin/../lib/gcc/x86_64-pc-linux-gnu/9.1.0/../../../../include/c++/9.1.0/bits/stl_uninitialized.h:83:8: note: in instantiation of function template specialization
      'std::_Construct<foo,foo>' requested here
                std::_Construct(std::__addressof(*__cur),*__first);
                     ^
/usr/sup/bin/../lib/gcc/x86_64-pc-linux-gnu/9.1.0/../../../../include/c++/9.1.0/bits/stl_uninitialized.h:134:2: note: in instantiation of function template specialization
      'std::__uninitialized_copy<false>::__uninit_copy<std::move_iterator<foo *>,foo *>' requested here
        __uninit_copy(__first,__last,__result);
        ^
/usr/sup/bin/../lib/gcc/x86_64-pc-linux-gnu/9.1.0/../../../../include/c++/9.1.0/bits/stl_uninitialized.h:289:19: note: in instantiation of function template specialization
      'std::uninitialized_copy<std::move_iterator<foo *>,foo *>' requested here
    { return std::uninitialized_copy(__first,__result); }
                  ^
/usr/sup/bin/../lib/gcc/x86_64-pc-linux-gnu/9.1.0/../../../../include/c++/9.1.0/bits/stl_uninitialized.h:310:19: note: in instantiation of function template specialization
      'std::__uninitialized_copy_a<std::move_iterator<foo *>,foo *,foo>' requested here
      return std::__uninitialized_copy_a
                  ^
/usr/sup/bin/../lib/gcc/x86_64-pc-linux-gnu/9.1.0/../../../../include/c++/9.1.0/bits/vector.tcc:473:10: note: in instantiation of function template specialization
      'std::__uninitialized_move_if_noexcept_a<foo *,std::allocator<foo> >' requested here
                = std::__uninitialized_move_if_noexcept_a
                       ^
/usr/sup/bin/../lib/gcc/x86_64-pc-linux-gnu/9.1.0/../../../../include/c++/9.1.0/bits/vector.tcc:121:4: note: in instantiation of function template specialization 'std::vector<foo,std::allocator<foo> >::_M_realloc_insert<int>' requested here
          _M_realloc_insert(end(),std::forward<_Args>(__args)...);
          ^
demo.cpp:15:9: note: in instantiation of function template specialization 'std::vector<foo,std::allocator<foo> >::emplace_back<int>' requested here
    bar.emplace_back(1);
        ^
demo.cpp:8:16: note: copy constructor of 'foo' is implicitly deleted because field 'b' has a deleted copy constructor
    std::mutex b;
               ^
/usr/sup/bin/../lib/gcc/x86_64-pc-linux-gnu/9.1.0/../../../../include/c++/9.1.0/bits/std_mutex.h:94:5: note: 'mutex' has been explicitly marked deleted here
    mutex(const mutex&) = delete;
    ^
1 error generated.

对此有任何想法吗?我希望使代码相对简单,但是我不确定如何使标准向量发挥作用,或者至少正确使用它。

ysll2009 回答:如果结构包含互斥量,则C ++将初始化程序列表推入标准向量的问题

问题在于foo的代码实例中是按值传递的。因此,当您将某些内容放入向量中时,需要创建一个副本。避免这种情况的一种简单方法是将指向foo的指针放入向量中。您可以将指针包装到某种引用计数机制中,从而不必跟踪释放对象的情况。

这是一个使用std::unique_ptr的简短示例,当向量超出范围时,它将自动删除向量中的所有foo实例:

#include <mutex>
#include <vector>
#include <memory>
#include <iostream>
#include <functional>

struct foo {
   foo(int A) : a(A) {}
   int a;
   std::mutex b;
};

void fixed_demo () {
   std::vector<std::unique_ptr<foo>> bar;

   std::unique_ptr<foo> p(new foo(1));
   bar.push_back(std::move(p));
   bar.emplace_back(new foo(2));
   for (auto it = bar.begin(); it != bar.end(); ++it) {
      (*it)->b.lock();
      std::cout << (*it)->a << std::endl;
      (*it)->b.unlock();
   }
}

int main () {
   fixed_demo();
   return 0;
}
,

查看其中一种解决方案后,我认为实际上该解决方案最适合我要的解决方案。如果没有上述有用的建议,我将无法解决。

#include <mutex>
#include <vector>

struct foo {
    int a;
    std::mutex b;

    foo (int a) : a(a) {;} 
    foo (const foo &f) : a(f.a) {;}
};

void other_fixed_demo () 
{
    std::vector<foo> bar;
    bar.emplace_back(1);
}

int main () {
    other_fixed_demo();
}

我不能说为什么,但是显然这里发生了两件事。首先,我们使用1输入调用构造函数,然后在emplace_back()中的某个地方调用拷贝构造函数。两者都不需要在创建结构的每种方式中明确地不包含互斥体,并且上述解决方案可以避免这种情况。

本文链接:https://www.f2er.com/3083411.html

大家都在问