std::atomic 作为类成员:使用 boost/python.hpp 时使用已删除的函数错误
Posted
技术标签:
【中文标题】std::atomic 作为类成员:使用 boost/python.hpp 时使用已删除的函数错误【英文标题】:std::atomic as class member: use of deleted function error when using boost/python.hpp 【发布时间】:2020-07-29 04:52:07 【问题描述】:其他看似相关的问题似乎可以通过直接初始化原子来解决:
std::atomic_uint32_t v10;
但是,当我将 std::atomic 变量作为类成员时,我仍然会收到“使用已删除函数”错误。我也只在使用 Boost Python 包装我的类以便它可以从 Python 调用时得到错误。我认为这是因为 Boost Python 应用了额外的编译规则,而不是 Boost Python 的一些问题。
AtomicTest.cpp
#include "AtomicTest.h"
#include <boost/python.hpp>
using namespace boost::python;
void AtomicTest::init()
printf("Atomic test\n");
BOOST_PYTHON_MODULE(atomicTest)
class_<AtomicTest>("AtomicTest")
.def("init", &AtomicTest::init)
;
;
AtomicTest.h
#ifndef ATOMICTEST_ATOMICTEST_H
#define ATOMICTEST_ATOMICTEST_H
#include <atomic>
class AtomicTest
public:
void init();
std::atomic_uint32_t v10;
;
#endif //ATOMICTEST_ATOMICTEST_H
构建日志:
In file included from /usr/include/boost/preprocessor/iteration/detail/iter/forward1.hpp:52:0,
from /usr/include/boost/python/object/value_holder.hpp:46,
from /usr/include/boost/python/object/class_metadata.hpp:14,
from /usr/include/boost/python/class.hpp:23,
from /usr/include/boost/python.hpp:18,
from /home/tb/CLionProjects/atomicTest/AtomicTest.cpp:6:
/usr/include/boost/python/object/value_holder.hpp: In instantiation of ‘boost::python::objects::value_holder<Value>::value_holder(PyObject*, A0) [with A0 = boost::reference_wrapper<const AtomicTest>; Value = AtomicTest; PyObject = _object]’:
/usr/include/boost/python/object/make_instance.hpp:72:16: required from ‘static Holder* boost::python::objects::make_instance<T, Holder>::construct(void*, PyObject*, boost::reference_wrapper<const T>) [with T = AtomicTest; Holder = boost::python::objects::value_holder<AtomicTest>; PyObject = _object]’
/usr/include/boost/python/object/make_instance.hpp:46:31: required from ‘static PyObject* boost::python::objects::make_instance_impl<T, Holder, Derived>::execute(Arg&) [with Arg = const boost::reference_wrapper<const AtomicTest>; T = AtomicTest; Holder = boost::python::objects::value_holder<AtomicTest>; Derived = boost::python::objects::make_instance<AtomicTest, boost::python::objects::value_holder<AtomicTest> >; PyObject = _object]’
/usr/include/boost/python/object/class_wrapper.hpp:29:37: required from ‘static PyObject* boost::python::objects::class_cref_wrapper<Src, MakeInstance>::convert(const Src&) [with Src = AtomicTest; MakeInstance = boost::python::objects::make_instance<AtomicTest, boost::python::objects::value_holder<AtomicTest> >; PyObject = _object]’
/usr/include/boost/python/converter/as_to_python_function.hpp:27:61: required from ‘static PyObject* boost::python::converter::as_to_python_function<T, ToPython>::convert(const void*) [with T = AtomicTest; ToPython = boost::python::objects::class_cref_wrapper<AtomicTest, boost::python::objects::make_instance<AtomicTest, boost::python::objects::value_holder<AtomicTest> > >; PyObject = _object]’
/usr/include/boost/python/to_python_converter.hpp:83:9: [ skipping 2 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/usr/include/boost/python/object/class_metadata.hpp:227:55: required from ‘static void boost::python::objects::class_metadata<T, X1, X2, X3>::register_aux2(T2*, Callback) [with T2 = AtomicTest; Callback = boost::integral_constant<bool, false>; T = AtomicTest; X1 = boost::python::detail::not_specified; X2 = boost::python::detail::not_specified; X3 = boost::python::detail::not_specified]’
/usr/include/boost/python/object/class_metadata.hpp:218:38: required from ‘static void boost::python::objects::class_metadata<T, X1, X2, X3>::register_aux(void*) [with T = AtomicTest; X1 = boost::python::detail::not_specified; X2 = boost::python::detail::not_specified; X3 = boost::python::detail::not_specified]’
/usr/include/boost/python/object/class_metadata.hpp:204:37: required from ‘static void boost::python::objects::class_metadata<T, X1, X2, X3>::register_() [with T = AtomicTest; X1 = boost::python::detail::not_specified; X2 = boost::python::detail::not_specified; X3 = boost::python::detail::not_specified]’
/usr/include/boost/python/class.hpp:450:28: required from ‘void boost::python::class_<T, X1, X2, X3>::initialize(const DefVisitor&) [with DefVisitor = boost::python::init<>; W = AtomicTest; X1 = boost::python::detail::not_specified; X2 = boost::python::detail::not_specified; X3 = boost::python::detail::not_specified]’
/usr/include/boost/python/class.hpp:583:5: required from ‘boost::python::class_<T, X1, X2, X3>::class_(const char*, const char*) [with W = AtomicTest; X1 = boost::python::detail::not_specified; X2 = boost::python::detail::not_specified; X3 = boost::python::detail::not_specified]’
/home/tb/CLionProjects/atomicTest/AtomicTest.cpp:17:48: required from here
/usr/include/boost/python/object/value_holder.hpp:133:13: error: use of deleted function ‘AtomicTest::AtomicTest(const AtomicTest&)’
BOOST_PP_REPEAT_1ST(N, BOOST_PYTHON_UNFORWARD_LOCAL, nil)
^
In file included from /home/tb/CLionProjects/atomicTest/AtomicTest.cpp:5:0:
/home/tb/CLionProjects/atomicTest/AtomicTest.h:10:7: note: ‘AtomicTest::AtomicTest(const AtomicTest&)’ is implicitly deleted because the default definition would be ill-formed:
class AtomicTest
^~~~~~~~~~
/home/tb/CLionProjects/atomicTest/AtomicTest.h:10:7: error: use of deleted function ‘std::atomic<unsigned int>::atomic(const std::atomic<unsigned int>&)’
In file included from /home/tb/CLionProjects/atomicTest/AtomicTest.h:8:0,
from /home/tb/CLionProjects/atomicTest/AtomicTest.cpp:5:
/usr/include/c++/7/atomic:691:7: note: declared here
atomic(const atomic&) = delete;
【问题讨论】:
【参考方案1】:当 Python 接口初始化其可从 Python 获得的对象时,它会复制您的对象。由于您的类具有默认的复制构造函数,因此它也会复制每个字段,并且原子对象没有复制构造函数(或赋值),对于good reason。
去这里的方法是告诉boost
不要使用副本,使用noncopyable(必须在那里搜索)。这个问题以boost::python: compilation fails because copy constructor is private 为例,在您的情况下,您需要更改class_
定义:
class_<AtomicTest, boost::noncopyable>("AtomicTest")
您也可以选择将您的原子序数保存在(共享)指针中,以便所有副本看起来都相同。这在一些将多个对象同步到同一个计数器的设计中通常是有意义的:
class AtomicTest
public:
AtomicTest() : v1(std::make_shared<std::atomic_uint32_t>(0))
void init();
std::shared_ptr<std::atomic_uint32_t> v1;
;
如果您的用例是一个单独计数的对象,那么noncopyable
可能更合适。
【讨论】:
boost::noncopyable 解决了很多编译器错误。谢谢!【参考方案2】:这是有道理的,您只需要对代码进行一些调整即可编译它
std::atomic_uint32_t == std::atomic<std::uint32_t>
如果你看标题https://en.cppreference.com/w/cpp/header/atomic
下 整数类型的 std::atomic 特化
atomic(const atomic&) = delete;
atomic& operator=(const atomic&) = delete;
atomic& operator=(const atomic&) volatile = delete;
另请参阅此参考 https://en.cppreference.com/w/cpp/atomic/atomic/atomic
原子变量不是 CopyConstructible。
警告:下面不安全
但是买家要注意这个操作不会是原子的并且可能会变得很奇怪
阅读此答案以了解有关原子不可复制的更多原因 Why are std::atomic objects not copyable?
所以理论上你可以做的是显式定义一个复制构造函数并这样做
AtomicTest::AtomicTest(const AtomicTest& origin)
: v1(origin.v1.load())
//... more explicit copying
【讨论】:
我不建议为原子内容提供复制构造函数。你提到了为什么不这样做的原因。 是的,我同意。不知道boost::noncopyable
。很好的发现。这是更好的答案以上是关于std::atomic 作为类成员:使用 boost/python.hpp 时使用已删除的函数错误的主要内容,如果未能解决你的问题,请参考以下文章
将 std::atomic_flag 包装在 getter/setter 中会使其“原子性”无效吗?