为什么 std::set::insert() 使用错误参数调用 operator<()
Why does std::set::insert() call operator<() with bad parameter
我需要帮助来理解为什么 std::set<T>::insert(T)
使用无效引用作为第二个参数调用 operator<(const T&, const T&)
,在我第一次插入时创建段错误。
这里是 class 我要插入集合的对象:
/**
* A CPC category.
*/
class Category {
private:
char m_section;
int m_class;
char m_subclass;
int m_group;
int m_subgroup;
public:
Category();
Category(char t_section, int t_class, char t_subclass, int t_group,
int t_subgroup);
char get_section() const;
int get_class() const;
char get_subclass() const;
int get_group() const;
int get_subgroup() const;
};
这是我的operator<
(抱歉,不是有史以来最干净的方法):
/**
* Obeys simple lexical order. A smaller-than operator for Category is
* required to allow objects to be placed in an std::set.
*/
bool operator<(const Category& cat1, const Category& cat2)
{
return (cat1.get_section() == cat2.get_section() ?
cat1.get_class() == cat2.get_class() ?
cat1.get_subclass() == cat2.get_subclass() ?
cat1.get_group() == cat2.get_group() ?
cat1.get_subgroup() == cat2.get_subgroup() ?
true :
cat1.get_subgroup() < cat2.get_subgroup() :
cat1.get_group() < cat2.get_group() :
cat1.get_subclass() < cat2.get_subclass() :
cat1.get_class() < cat2.get_class() :
cat1.get_section() < cat2.get_section());
}
这是创建集合的代码:
std::istream& operator>> (std::istream& is, CategorySet& cs)
{
std::set<Category>* cats;
Category cat;
while (is >> cat) {
cats->insert(cat);
}
cs = CategorySet{ cats };
return is;
}
我在cats->insert(cat);
之前放了一个断点:
Breakpoint 1, InnovationModelling::operator>> (is=..., cs=...) at lib/PatentData.cpp:126
126 cats->insert(cat);
(gdb) p *cats
= std::set with 0 elements
(gdb) p cat
= {m_section = 65 'A', m_class = 1, m_subclass = 65 'A', m_group = 1, m_subgroup = 0}
(gdb) ptype cat
type = class InnovationModelling::Category {
private:
char m_section;
int m_class;
char m_subclass;
int m_group;
int m_subgroup;
public:
Category(void);
Category(char, int, char, int, int);
char get_section(void) const;
int get_class(void) const;
char get_subclass(void) const;
int get_group(void) const;
int get_subgroup(void) const;
}
(上面的</code>是因为我此时忘记显示集合为空所以我再次运行程序。)</p>
<p>然后我遍历 <code>std::set
的东西,直到它调用 operator()
,它没有超载:
(gdb) s
std::less<InnovationModelling::Category>::operator() (this=0x5555555993c0 <std::cout@@GLIBCXX_3.4>, __x=..., __y=...)
at /usr/include/c++/10.2.0/bits/stl_function.h:386
386 { return __x < __y; }
(gdb) p __x
= (const InnovationModelling::Category &) @0x7fffffffd3b0: {m_section = 65 'A', m_class = 1, m_subclass = 65 'A', m_group = 1,
m_subgroup = 0}
(gdb) p __y
= (const InnovationModelling::Category &) <error reading variable>
果然,operator<
被调用时使用了这个无效的引用,因此 get_section()
最终被调用并出现段错误:
(gdb) s
InnovationModelling::Category::get_section (this=0x26) at lib/PatentData.cpp:187
187 return m_section;
(gdb) p this
= (const InnovationModelling::Category * const) 0x26
(gdb) p *this
Cannot access memory at address 0x26
(gdb) s
Program received signal SIGSEGV, Segmentation fault.
0x0000555555568412 in InnovationModelling::Category::get_section (this=0x26) at lib/PatentData.cpp:187
如果 std::set::insert()
的作用很明显,我很抱歉,但我是 C++ 的初学者,我什至无法理解它觉得有必要这样做的事实完全调用 operator<()
以在空集中插入内容。
And here is the code creating the set:
'不怕。
您创建了一个 pointer-to-set,但它实际上并未指向任何集合;它只是一个未初始化的指针。
您可以使用 new
动态分配集合,但除非万不得已,否则不要这样做。事实上,除非万不得已,否则不要使用指针。您在这里的需求将由 CategorySet
(我们对此一无所知)驱动,但如果您可以让您的设置成为一个不错的局部变量,生活就会容易得多。
我需要帮助来理解为什么 std::set<T>::insert(T)
使用无效引用作为第二个参数调用 operator<(const T&, const T&)
,在我第一次插入时创建段错误。
这里是 class 我要插入集合的对象:
/**
* A CPC category.
*/
class Category {
private:
char m_section;
int m_class;
char m_subclass;
int m_group;
int m_subgroup;
public:
Category();
Category(char t_section, int t_class, char t_subclass, int t_group,
int t_subgroup);
char get_section() const;
int get_class() const;
char get_subclass() const;
int get_group() const;
int get_subgroup() const;
};
这是我的operator<
(抱歉,不是有史以来最干净的方法):
/**
* Obeys simple lexical order. A smaller-than operator for Category is
* required to allow objects to be placed in an std::set.
*/
bool operator<(const Category& cat1, const Category& cat2)
{
return (cat1.get_section() == cat2.get_section() ?
cat1.get_class() == cat2.get_class() ?
cat1.get_subclass() == cat2.get_subclass() ?
cat1.get_group() == cat2.get_group() ?
cat1.get_subgroup() == cat2.get_subgroup() ?
true :
cat1.get_subgroup() < cat2.get_subgroup() :
cat1.get_group() < cat2.get_group() :
cat1.get_subclass() < cat2.get_subclass() :
cat1.get_class() < cat2.get_class() :
cat1.get_section() < cat2.get_section());
}
这是创建集合的代码:
std::istream& operator>> (std::istream& is, CategorySet& cs)
{
std::set<Category>* cats;
Category cat;
while (is >> cat) {
cats->insert(cat);
}
cs = CategorySet{ cats };
return is;
}
我在cats->insert(cat);
之前放了一个断点:
Breakpoint 1, InnovationModelling::operator>> (is=..., cs=...) at lib/PatentData.cpp:126
126 cats->insert(cat);
(gdb) p *cats
= std::set with 0 elements
(gdb) p cat
= {m_section = 65 'A', m_class = 1, m_subclass = 65 'A', m_group = 1, m_subgroup = 0}
(gdb) ptype cat
type = class InnovationModelling::Category {
private:
char m_section;
int m_class;
char m_subclass;
int m_group;
int m_subgroup;
public:
Category(void);
Category(char, int, char, int, int);
char get_section(void) const;
int get_class(void) const;
char get_subclass(void) const;
int get_group(void) const;
int get_subgroup(void) const;
}
(上面的</code>是因为我此时忘记显示集合为空所以我再次运行程序。)</p>
<p>然后我遍历 <code>std::set
的东西,直到它调用 operator()
,它没有超载:
(gdb) s
std::less<InnovationModelling::Category>::operator() (this=0x5555555993c0 <std::cout@@GLIBCXX_3.4>, __x=..., __y=...)
at /usr/include/c++/10.2.0/bits/stl_function.h:386
386 { return __x < __y; }
(gdb) p __x
= (const InnovationModelling::Category &) @0x7fffffffd3b0: {m_section = 65 'A', m_class = 1, m_subclass = 65 'A', m_group = 1,
m_subgroup = 0}
(gdb) p __y
= (const InnovationModelling::Category &) <error reading variable>
果然,operator<
被调用时使用了这个无效的引用,因此 get_section()
最终被调用并出现段错误:
(gdb) s
InnovationModelling::Category::get_section (this=0x26) at lib/PatentData.cpp:187
187 return m_section;
(gdb) p this
= (const InnovationModelling::Category * const) 0x26
(gdb) p *this
Cannot access memory at address 0x26
(gdb) s
Program received signal SIGSEGV, Segmentation fault.
0x0000555555568412 in InnovationModelling::Category::get_section (this=0x26) at lib/PatentData.cpp:187
如果 std::set::insert()
的作用很明显,我很抱歉,但我是 C++ 的初学者,我什至无法理解它觉得有必要这样做的事实完全调用 operator<()
以在空集中插入内容。
And here is the code creating the set:
'不怕。
您创建了一个 pointer-to-set,但它实际上并未指向任何集合;它只是一个未初始化的指针。
您可以使用 new
动态分配集合,但除非万不得已,否则不要这样做。事实上,除非万不得已,否则不要使用指针。您在这里的需求将由 CategorySet
(我们对此一无所知)驱动,但如果您可以让您的设置成为一个不错的局部变量,生活就会容易得多。