我需要在我的代码中使用原子shared_ptr - 我有单读者多编写器场景,其中一个小数据结构将被多个线程复制和覆盖。
在看到this和this(以及我自己的测试)之后,似乎自由原子功能在GCC 4.9.2中仍无效。
我试过简单地将shared_ptr放在原子中:
#include <atomic>
#include <iostream>
#include <memory>
std::atomic<std::shared_ptr<std::string> > a_var;
void place() {
std::shared_ptr<std::string> ptr1(new std::string("abc"));
a_var.store(ptr1);
}
int main(int argc, const char *argv[]) {
place();
std::shared_ptr<std::string> ptr2 = a_var.load();
std::cout<< *ptr2 << std::endl;
return 0;
}
但是在使用g++ --std=c++11 -g <filename> -latomic
进行编译后,它会引发段错误。
似乎正在发生的事情是,在调用store
之后,使用复制构造函数创建了新的shared_ptr
,但它立即被删除,并且在退出place
ptr1之后被释放,因此{{ 1}}抛出。
任何想法如何使其发挥作用
答案 0 :(得分:4)
std::atomic<.>
只能用于“平凡的可复制类型”。
std::shared_ptr<std::string>
显然不符合这些标准。某处atomic
将对象复制为一块内存并违反一个或多个类的某些不变量。
例如我们都知道:
std::shared_ptr<std::string> s(new std::string("abc"));
std::shared_ptr<std::string> t;
memcpy(&t,&s,sizeof(std::shared_ptr<std::string>));
复制结束时是否可编译和可执行。它也是灾难的保证配方。
在你的情况下ptr1
没有“知道”它已被复制,所以当它(ptr1
)超出范围时它会删除字符串。然后你访问字符串。的动臂。游戏结束。
实现目标的标准方法是使用share_ptr
保护std::mutex
。没有简单的方法来提供指向字符串的无锁指针。这样的对象将迎来计算革命。
答案 1 :(得分:2)
暂时忘掉C ++ 11闪亮的玩具,看看你真正想要实现的目标。
这里要保护的是你的数据结构,而不是引用它的指针。
我假设“自由原子功能”你的意思是无锁。有一个很好的理由为什么编译器不会让你过于自由地抛出原子。这是因为除了最罕见的情况之外,在除了使用普通旧的阻塞同步之外,效率较低。
C ++ 11使用原子变量玩弄时尚的最新奇思妙想,但是虽然这些东西被包裹成一层漂亮的语法糖,但它的血腥危险并且当被任何人使用时会导致设计不稳定和/或效率低下经验丰富的专家。
在C ++ 14中,你将拥有atomic_shared_pointer
,这需要自定义代码,当然不能仅仅通过将共享指针包装到原子模板中来实现,但无论如何这都无法解决你的问题也是。