std::atomic_int 出现“使用已删除函数”错误
Posted
技术标签:
【中文标题】std::atomic_int 出现“使用已删除函数”错误【英文标题】:"Use of deleted function" error with std::atomic_int 【发布时间】:2015-02-03 12:58:01 【问题描述】:我想使用std::atomic_int
变量。在我的代码中,我有:
#include <atomic>
std::atomic_int stop = 0;
int main()
// Do something
这给了我一个编译错误:
use of deleted function 'std::__atomic_base<_IntTp>::__atomic_base(const std::__atomic_base<_IntTp>&) [with _ITp = int]'
std::atomic_int stop = 0;
^
知道发生了什么吗?
【问题讨论】:
肯定 boost/thread.hpp 在这里无关紧要吗?删除标头后问题是否仍然存在? 是的,它与 boost 无关……不知道为什么我把它包括在内!即使删除标题后问题仍然存在。 显然编译器认为你正在做std::atomic_int stop = std::atomic_int(0);
,并且由于复制构造函数被删除,这将不起作用。而是尝试直接初始化,例如std::atomic_int stop0;
。
复制初始化需要一个可访问的复制构造函数
@JoachimPileborg:是的,我总是忘记这条规则。标准版现已在下方提供。
【参考方案1】:
您的代码试图在 RHS 上构造一个临时的std::atomic_int
,然后使用std::atomic_int
复制构造函数(即delete
d)初始化stop
,如下所示:
std::atomic_int stop = std::atomic_int(0);
这是因为复制初始化,正如您在此处执行的那样,并不完全等同于其他类型的初始化。
[C++11: 8.5/16]:
初始化器的语义如下[..]如果初始化器是(非括号)大括号初始化列表,则对象或引用是列表初始化(8.5.4)。
(这允许选项 3,在此答案的末尾)
[..]
如果目标类型是(可能是 cv 限定的)类类型:
如果初始化是直接初始化,或者如果是copy-initialization,其中源类型的 cv 非限定版本与,或目标类的派生类,考虑构造函数。 枚举适用的构造函数 (13.3.1.3),并通过重载决议 (13.3) 选择最佳构造函数。调用如此选择的构造函数来初始化对象,使用初始化表达式或表达式列表作为其参数。如果没有构造函数适用,或者重载决议不明确,则初始化格式错误。
(这几乎描述了您的代码,但不完全;这里的关键是,可能与直觉相反,std::atomic_int
的构造函数在您的情况下根本没有考虑!)
否则(即,对于剩余的 复制初始化 情况),用户定义的转换序列可以从源类型转换为目标类型或(当使用转换函数时)转换为其派生类如 13.3.1.4 中所述枚举,并通过重载决议 (13.3) 选择最佳的。如果转换无法完成或不明确,则初始化格式错误。 使用初始化表达式作为参数调用所选函数;如果函数是构造函数,则调用初始化目标类型的 cv 非限定版本的临时版本。临时是prvalue。 调用的结果(对于构造函数来说是临时的)然后用于direct-initialize,根据上面的规则,作为目标的对象复制初始化。在某些情况下,允许实现通过将中间结果直接构造到正在初始化的对象中来消除此直接初始化中固有的复制;见 12.2、12.8。
(这是您的方案;因此,尽管可以省略副本,但它仍然必须是可能的)
[..]
无论如何,这就是解决方法;使用直接初始化或列表初始化:
std::atomic_int stop(0); // option 1
std::atomic_int stop0; // option 2
std::atomic_int stop = 0; // option 3
【讨论】:
是的,谢谢。因此,似乎不存在没有任何参数的默认构造函数,您需要提供一个明确的值。谢谢! @Karnivaurus:它与任何默认构造函数无关。您正在提供论据。 大多数类型不都是这样吗?T a = x;
创建一个从 x
构造的临时 T
,然后从该临时初始化 a
。复制省略可能会消除临时性,但复制构造函数必须仍然可用。
啊,是的,我找到了措辞。标准来袭!
还有选项 3:std::atomic_int stop = 0;
。这是复制初始化,但是使用花括号初始化列表的复制初始化执行复制列表初始化,它不涉及临时变量(在这种情况下)。【参考方案2】:
就我而言,我有以下错误(示例):
• 'std::literals' 尚未声明
using namespace std::literals::string_literals;
• std::random_device 出现“使用已删除函数”错误
std::random_device device = std::random_device
检查您选择的 C++ 标准是什么。在我的调试模式下,我选择了 -std=c++17, ALL OK。但是在发布模式下,我选择了 -std:c++11,有很多错误。
更新 通过远程 Linux 编译在 Clion Windows 2018.3 上测试。
使用 -std=c++11
使用 -std=c++17
C ++ 是一个不断发展的标准:2003 年之后有 2011 年 (C ++ 11),然后是 2014 年 (C ++ 14),现在我们有了 2017 年 (C ++ 17),我们正在为 2020 年 (C ++ 20)。许多事情正在发生变化,它们已被弃用,其他功能是新的。如果你想要最新的更新,你应该使用最新的标准,如果你的软件有可能被弃用的代码,那么你必须使用创建它的标准。
【讨论】:
好的,那我们换个方式试试吧。这个答案如何解决有关初始化std::atomic_int
的问题?
您的回答有其优点,因为您说发布的代码在较新的标准(C++17)中按预期工作,并且鉴于这是一个老问题,这是一个很好的补充。但是,我同意有很多与原始问题无关的噪音(string_literals、random_device、clion、cmake)
确实有很多噪音,但是没有人开始C++编程什么都知道。有些人从 0 开始,对 C++ 的所有问题和特性一无所知。
评论“这似乎不相关”并不是贬低,而是为了鼓励您通过使更相关来改进您的答案,在这种情况下要么通过澄清或简化它。像这样的问题的答案不应该是“完整的说明手册”;如果答案清晰且中肯,答案会更有用。如果人们需要 C++17 方面的帮助,本网站上还有其他答案可以更直接、更全面地解决问题。
这并没有解释 C++17 中的哪些变化使得使用 = 0
初始化原子变量是合法的。答案读起来就像您说您在std::random_device
中遇到了类似的“使用已删除功能”错误。没有任何地方(除了在整个开发环境的那些难以阅读的小图片中)这个答案实际上说 C++17 使问题中的代码编译。 (不过是这样。godbolt.org/z/uNswJL。即使-std=gnu++14
也不使其合法,所以它是 C++17 中的新东西。)以上是关于std::atomic_int 出现“使用已删除函数”错误的主要内容,如果未能解决你的问题,请参考以下文章
统计一篇英文文章内每个单词出现频率,并返回出现频率最高的前10个单词及其出现次数