含atomic成员的对象容器编译错误解决方法咨询
解决包含std::atomic成员的对象存储到容器的编译错误
问题根源
std::atomic从C++11开始就被设计为不可拷贝、不可移动的类型——标准库显式删除了它的拷贝构造/赋值函数,也没有提供移动操作。这是因为拷贝原子变量会破坏其核心的原子语义:原子操作的意义在于保证多线程下的状态一致性,而拷贝动作本身无法被原子化,会引发竞态条件。
你的代码里两个编译错误都源于此:
std::list<S> l2 = l1:容器拷贝需要元素支持拷贝构造,但S因包含std::atomic成员,默认生成的拷贝构造被禁用。std::make_shared<S>(s1):尝试用s1拷贝构造新的S对象,同样触发禁用的拷贝构造。
解决方案
方案1:给S添加移动构造/赋值,直接存储对象
如果想直接在容器里存储S对象,可以手动实现S的移动构造和移动赋值,通过原子操作转移状态,避免拷贝:
#include <atomic> #include <list> struct S { std::atomic<int> n_{0}; // 移动构造:用exchange原子转移原对象的值,同时重置原对象的原子变量 S(S&& other) noexcept : n_(other.n_.exchange(0)) {} // 移动赋值 S& operator=(S&& other) noexcept { if (this != &other) { n_.store(other.n_.exchange(0)); } return *this; } // 保留默认构造函数 S() = default; }; int main() { std::list<S> l1; // 用emplace_back直接在容器内构造元素,无需拷贝/移动 l1.emplace_back(); // 支持移动容器(若要复制容器,需手动遍历构造新元素) std::list<S> l2 = std::move(l1); // 向容器添加元素:移动已有的S对象 S s1; s1.n_.store(42); l2.push_back(std::move(s1)); // 移动后s1的n_会被设为0 }
方案2:存储智能指针(更简单的常用方案)
如果不需要直接存储对象本身,用std::shared_ptr或std::unique_ptr包裹S是更省心的选择——智能指针的拷贝/移动不会涉及S对象的拷贝,只是管理对象的所有权:
#include <atomic> #include <list> #include <memory> struct S { std::atomic<int> n_{0}; }; int main() { std::list<std::shared_ptr<S>> l; // 直接构造新的S对象,无需拷贝 auto ss1 = std::make_shared<S>(); ss1->n_.store(42); l.push_back(ss1); // 若要基于已有S的状态创建新对象,手动原子复制值 S s1; s1.n_.store(100); auto ss2 = std::make_shared<S>(); ss2->n_.store(s1.n_.load()); // 原子加载s1的值到新对象 l.push_back(ss2); }
关键注意事项
- 永远不要尝试绕过
std::atomic的拷贝限制(比如用memcpy),这会导致未定义行为,彻底破坏原子语义。 - 使用移动构造时,要明确移动后原对象的原子变量会被重置(示例中用
exchange(0)),确保原对象处于有效状态。 - 多线程场景下,存储智能指针的方案更易维护:智能指针负责线程安全的所有权管理,
std::atomic负责对象内部状态的原子操作。
内容的提问来源于stack exchange,提问作者PrueWho
相关产品推荐
相关产品推荐

