无法在两个C++类间共享容器:问题复现与求助
问题:生产者消费者共享容器无数据交互
尝试在生产者类Foo1、消费者类Foo2之间通过std::shared_ptr共享容器,生产者向绑定key的队列推数据,消费者读取时始终无数据。无编译错误,但运行结果不符合预期。
可复现代码
main.cpp
#include "foo_1.h" #include "foo_2.h" #include <iostream> Foo1 foo1; Foo2 foo2; int main(int argc, char* argv[]) { std::queue<shared_container> q; SharedContainer map = *g_map; // 1是本示例中预设的key,绑定空队列 map[1] = q; // 向队列插入数据,预期队列大小=1 foo1.producer(); // 读取队列,预期大小=1,实际为0 foo2.consumer(); // 再次插入数据,预期队列大小=2,实际为1 foo1.producer(); // 读取队列,预期大小=2,实际为0 foo2.consumer(); return 0; }
foo_2.h
#ifndef FOO_2_H #define FOO_2_H #include "shared_container.h" #include <iostream> class Foo2 { public: Foo2() { } static void consumer(void) { SharedContainer map = *g_map; // 读取预设key=1对应的队列 auto node_q = &map[1]; std::cout << "[consumer] size of queue=" << node_q->size() << std::endl; } }; #endif // FOO_2_H
foo_1.h
#ifndef FOO_1_H #define FOO_1_H #include "shared_container.h" #include <iostream> class Foo1 { public: Foo1() { } static void producer(void) { SharedContainer map = *g_map; // 向预设key=1对应的队列写入数据 auto node_q = &map[1]; // 向队列添加数据 node_q->emplace(45); std::cout << "[producer] size of queue=" << node_q->size() << std::endl; } }; #endif // FOO_1_H
shared_container.h
#ifndef SHARED_CONTAINER_H #define SHARED_CONTAINER_H #include <memory> #include <queue> #include <unordered_map> struct shared_container { int x; shared_container(int x) { this->x = x; } }; using SharedContainer = std::unordered_map<int, std::queue<shared_container>>; inline std::shared_ptr<SharedContainer> g_map = std::make_shared<SharedContainer>(); #endif // SHARED_CONTAINER_H
编译运行结果
$ g++ -std=c++17 main.cpp -o test $ ./test [producer] size of queue=1 [consumer] size of queue=0 [producer] size of queue=1 [consumer] size of queue=0
问题原因
核心错误是每次操作的都是共享容器的副本,而非g_map指向的原容器:
- 在
main、producer、consumer中,都执行了SharedContainer map = *g_map;,这会创建g_map所指向容器的拷贝。 - 生产者向副本的队列中添加数据,消费者读取的是另一个副本的队列,自然看不到数据;
main里初始化的也是副本,和共享容器无关。
修复方案
直接操作g_map指向的原容器,通过指针或引用访问,避免拷贝:
修改后的代码
main.cpp
#include "foo_1.h" #include "foo_2.h" #include <iostream> Foo1 foo1; Foo2 foo2; int main(int argc, char* argv[]) { std::queue<shared_container> q; // 直接操作g_map指向的原容器 (*g_map)[1] = q; foo1.producer(); foo2.consumer(); foo1.producer(); foo2.consumer(); return 0; }
foo_1.h
#ifndef FOO_1_H #define FOO_1_H #include "shared_container.h" #include <iostream> class Foo1 { public: Foo1() { } static void producer(void) { // 直接获取原容器的引用,避免拷贝 SharedContainer& map = *g_map; auto& node_q = map[1]; // 用引用而非指针,更安全 node_q.emplace(45); std::cout << "[producer] size of queue=" << node_q.size() << std::endl; } }; #endif // FOO_1_H
foo_2.h
#ifndef FOO_2_H #define FOO_2_H #include "shared_container.h" #include <iostream> class Foo2 { public: Foo2() { } static void consumer(void) { // 直接获取原容器的引用 SharedContainer& map = *g_map; auto& node_q = map[1]; std::cout << "[consumer] size of queue=" << node_q.size() << std::endl; } }; #endif // FOO_2_H
shared_container.h无需修改。
修复后运行结果
$ g++ -std=c++17 main.cpp -o test $ ./test [producer] size of queue=1 [consumer] size of queue=1 [producer] size of queue=2 [consumer] size of queue=2
内容的提问来源于stack exchange,提问作者rookie
相关产品推荐
相关产品推荐

