C++中通过set更新deque元素失败的问题求助
这个问题其实是C++容器存储模型的典型坑——你误以为std::set存的是原对象的引用,但实际上它存的是完全独立的副本!咱们一步步拆解原因和解决方案:
问题根源
当你执行set_list.insert(temp)时,std::set作为值语义的容器,会创建一个book对象的副本存入自身,而不是存储对deque中C的引用。所以set里的“C”和deque里的“C”是两个完全不相关的实例,修改其中一个自然不会影响另一个。你用const_cast修改set里的副本,只会改变这个独立对象的name,和deque里的原对象毫无关系。
解决方案
要实现两个容器的同步更新,核心是让它们指向同一个book对象,而不是各自存副本。这里有两种靠谱的做法:
方案一:用智能指针存储(推荐,安全无风险)
把deque和set的存储类型都改成std::shared_ptr<book>,这样两个容器里存的都是指向同一个book对象的指针,修改指针指向的内容,两个容器都会同步看到变化。
具体代码调整如下:
- 先调整容器类型:
// 将deque改为存储shared_ptr<book> std::deque<std::shared_ptr<book>> book_deque; // 初始化时用make_shared创建对象 book_deque.push_back(std::make_shared<book>(A)); book_deque.push_back(std::make_shared<book>(B)); book_deque.push_back(std::make_shared<book>(C)); // ... 继续初始化D到G // set也要改为存储shared_ptr,同时自定义比较器(因为默认set会比较指针地址,我们需要按book的x/y排序) struct BookPtrComparer { bool operator()(const std::shared_ptr<book>& lhs, const std::shared_ptr<book>& rhs) const { return *lhs < *rhs; // 复用你已实现的book::operator< } }; std::set<std::shared_ptr<book>, BookPtrComparer> book_set;
- 插入和修改操作:
// 获取deque中C的智能指针并插入set auto c_ptr = book_deque[2]; book_set.insert(c_ptr); // 遍历set修改对象 for (auto iter = book_set.begin(); iter != book_set.end(); ++iter) { // 直接比较指针地址,确保是同一个实例 if (*iter == c_ptr) { (*iter)->setName('T'); } }
这样修改后,deque里的C的name也会变成'T',因为两个容器指向的是同一个对象。
方案二:存储原始指针(谨慎使用)
如果不想用智能指针,也可以让set存储book*,但要注意deque的元素地址稳定性:deque在扩容时可能会移动元素,导致指针失效。所以只有当你的deque不会扩容(比如预先分配足够空间,或者不会插入删除元素)时,才适合用这种方式:
std::deque<book> book_deque; // 初始化book_deque... // set存储book*,自定义比较器按book的x/y排序 struct BookPtrComparer { bool operator()(const book* lhs, const book* rhs) const { return *lhs < *rhs; } }; std::set<book*, BookPtrComparer> book_set; // 插入deque中C的地址 book* c_ptr = &book_deque[2]; book_set.insert(c_ptr); // 修改对象 for (auto iter = book_set.begin(); iter != book_set.end(); ++iter) { if (*iter == c_ptr) { (*iter)->setName('T'); } }
这种方式要时刻留意deque元素的生命周期和地址变化,风险比智能指针高,不推荐在复杂业务场景使用。
额外注意点
你之前用const_cast修改set里的元素,虽然能编译,但如果修改的是影响operator<的x/y值,会破坏set的有序结构,导致后续操作出现未定义行为,一定要避免这种做法!
内容的提问来源于stack exchange,提问作者seenblee

