自定义对象的 STL 集,每个对象都包含一个 STL 集
从下面的代码中可以清楚地看出,我想要一组对象 objectSet,每个对象包含 str1 和 str2。该集合以 str1 为键,并且不会添加任何已在 objectSet 中具有 str1 的新对象,但如果这个新对象具有不同的 str2,我想跟踪我在 str2Set 中看到它的事实
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <set>
#include <map>
using namespace std;
class Object {
public:
string _str1;
string _str2;
set<string> _str2Set;
bool operator<(const Object& b) const {
return _str1 < b._str1;
}
};
int main(int argc, char *argv[]) {
set<Object> objectSet;
Object o;
o._str1 = "str1";
o._str2 = "str2";
pair< set<Object>::iterator, bool> o_ret = objectSet.insert(o);
if (o_ret.second == false) { // key exists
int temp = (*o_ret.first)._str2Set.size(); // this is apparently fine
(*o_ret.first)._str2Set.insert(o._str2); // this results in the error
}
return 0;
}
:编译器错误:
set_test.cpp:在函数“int main(int, char**)”中: set_test.cpp:31: 错误:传递 'const std::set, std::allocator >, std::less, std::allocator > >,std::分配器,std::分配器> > >'作为 'std::pair, _Compare, typename _Alloc::rebind<_Key>::other>::const_iterator, bool> 的 'this' 参数std::set<_Key, _Compare, _Alloc>::insert(const _Key&) [其中 _Key = std::basic_string, std::allocator >, _Compare = std::less, std::allocator > >, _Alloc = std::分配器, std::分配器 > >]' 丢弃限定符
我知道这与 const 有关,但我仍然无法确切地弄清楚问题是什么或如何解决它。仅仅摆脱 const 没有帮助。
作为替代方案,我尝试将我的对象存储在 中
map<string,Object> objectSet;
并且,奇怪的是,以下工作正常:
pair< map<string,Object>::iterator, bool> o_ret = objectSet.insert(pair<string,Object>(o._str1,o));
if (o_ret.second == false) { // key exists
o_ret.first->second._str2Set.insert(o._str2);
}
当然,这意味着我必须存储 str1 两次,我认为这是浪费。 感谢您的意见。
As is hopefully clear from the code below, I'd like to have a set of objects objectSet, each containing str1 and str2. The set is keyed on str1, and any new objects with an str1 already in the objectSet will not be added, but if this new object has a different str2, I want to keep track of the fact that I saw it in the str2Set
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <set>
#include <map>
using namespace std;
class Object {
public:
string _str1;
string _str2;
set<string> _str2Set;
bool operator<(const Object& b) const {
return _str1 < b._str1;
}
};
int main(int argc, char *argv[]) {
set<Object> objectSet;
Object o;
o._str1 = "str1";
o._str2 = "str2";
pair< set<Object>::iterator, bool> o_ret = objectSet.insert(o);
if (o_ret.second == false) { // key exists
int temp = (*o_ret.first)._str2Set.size(); // this is apparently fine
(*o_ret.first)._str2Set.insert(o._str2); // this results in the error
}
return 0;
}
Here is the compiler error:
set_test.cpp: In function ‘int main(int, char**)’:
set_test.cpp:31: error: passing ‘const std::set, std::allocator >, std::less, std::allocator > >, std::allocator, std::allocator > > >’ as ‘this’ argument of ‘std::pair, _Compare, typename _Alloc::rebind<_Key>::other>::const_iterator, bool> std::set<_Key, _Compare, _Alloc>::insert(const _Key&) [with _Key = std::basic_string, std::allocator >, _Compare = std::less, std::allocator > >, _Alloc = std::allocator, std::allocator > >]’ discards qualifiers
I understand this has to do with const but I still can't figure out exactly what the problem is or how to fix it. Just getting rid of the const doesn't help.
As an alternative, I tried storing my Object's in
map<string,Object> objectSet;
And, strangely enough, the following works just fine:
pair< map<string,Object>::iterator, bool> o_ret = objectSet.insert(pair<string,Object>(o._str1,o));
if (o_ret.second == false) { // key exists
o_ret.first->second._str2Set.insert(o._str2);
}
Of course, that means I have to store str1 twice, which I consider wasteful.
Thanks for your input.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
从集合插入返回的迭代器对于该对的第一个成员有一个常量迭代器 - 您不应该修改插入集合中的对象,因为如果修改影响顺序,就会发生不好的事情。所以对它调用 size 是可以的,因为这是一个 const 方法,但是 insert 是不行的,因为它修改了集合中的对象。
映射之所以有效,是因为对象是值,而不是键,因此您可以修改它而不影响映射的索引(在执行映射插入时会复制字符串)。
如果你想使用一个集合来存储你的对象并避免额外的字符串副本,更新它的方法是从集合中删除该对象(在删除它之前制作一个副本),更新副本,然后重新插入复制。当它在集合中时,您无法更新它。我目前没有 STL 参考资料,所以无法给您代码,但这是要遵循的总体思路。
The iterator you get back from a set insert has a const iterator for the first member of the pair - you're not supposed to modify the object you inserted in the set, because bad things will happen if the modification affects the order. So calling size on it is ok, because that's a const method, but insert is out because it modifies the object in the set.
The map works because the Object is the value, not the key, so you can modify it without affecting the indexing of the map (the string is copied when you did the map insert).
If you want to use a set to store your Objects and avoid the extra copy of string, the way to update it is to remove the Object from the set (making a copy before you delete it), update the copy, and then reinsert the copy. You can't update it while it's in the set. I'm away from my STL references at the moment so I can't give you code, but that's the general idea to follow.
其他答案已经正确说明了您的方法的问题,这是解决方案的想法。由于第一个字符串是您的密钥,因此请将您的主数据结构更改为以第一个字符串为键的
std::map
并携带其余数据作为有效负载:在某种意义上,第二个字符串是有点多余,你也许可以重新设计它以完全消除它:使用
find 代替
insert
,如果键已经存在,则附加第二个字符串到集合。The other answers already correctly stated the problem with your approach, here's an idea for a solution. Since the first string is your key, change your main data structure to a
std::map
keyed on the first string and carrying the rest of the data as the payload:In some sense the second string is a bit redundant, and you might be able to redesign this to do away with it entirely: Instead of
insert
usefind
, and if the key already exists, you append your second string to the set.在阅读了每个人的有用评论并学习了比我想象的更多的关于浅层常量和可变的知识之后,我意识到只需存储一个指向 _str2set 的指针就可以完成我想要的一切。我个人认为按照 @john 的建议声明它是可变的很好,但也许有些人会发现 ptr 解决方案不那么令人反感。
After reading everyone's helpful comments and learning way more than I thought I ever wanted to know about shallow constness and mutable, I realized I can accomplish everything I wanted simply by storing a pointer to the _str2set. I personally think that declaring it mutable as suggested by @john is fine, but maybe some people would find the ptr solution less objectionable.
你的设计有缺陷。您正在使用对象作为集合的键,但随后您尝试修改集合的键。当然,您只是修改了对象的部分,不会影响它作为键的使用,但编译器不知道这一点。你需要修改你的设计,你的第二个版本对我来说很好,我不担心存储两次字符串(通常,我不知道你的具体情况)。或者,您可以拆分对象,以便将键部分和值部分分开。最后,您可以将 _str2set 声明为可变的。
Your design is flawed. You are using Object as a key to a set, but then you are attempting to modify the keys of your set. Of course you are only modifying parts of Object that don't affect it's use as a key, but the compiler doesn't know that. You need to modify your design, your second version is fine to me, I wouldn't worry about storing the string twice (normally, I don't know your specific circumstances). Alternatively you could split your object so the key part and the value part are separated. Finally you could declare _str2set as mutable.
该错误表明
(*o_ret.first)._str2Set
是一个const
对象,并且您无法将其作为对象调用insert
方法。结果。这是完全正确的:由于不允许修改
std::set
中的对象(因为这可能会使容器的一致性失效),因此您会得到一个const
限定的对象将iterator
解引用到容器中时对象(就好像它是const_iterator
)。您还注意到它适用于
std::map
,但那是因为您正在修改那里的值,而不是键。请记住,在std::set
中,值是键,因此您无法修改它。The error says that
(*o_ret.first)._str2Set
is aconst
object, and that you cannot call theinsert
method for it as a result.And it's quite right : since you are not allowed to modify the objects in a
std::set
(because that would potentially invalidate the container's consistency), you get aconst
qualified object when dereferencing aniterator
into the container (as if it were aconst_iterator
).You also noted that it worked for a
std::map
, but that's because you're modifying the value there, not the key. Remember that in astd::set
, the value IS the key, so you can't modify it.